package com.xishu.service.order.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xishu.aop.Validator;
import com.xishu.bo.*;
import com.xishu.cash.QfPayClient;
import com.xishu.config.Config;
import com.xishu.config.Constant;
import com.xishu.dao.jpa.OrderDao;
import com.xishu.entity.LockOrderCashOrOrderItem;
import com.xishu.entity.User;
import com.xishu.entity.customer.Customer;
import com.xishu.entity.customer.CustomerTicket;
import com.xishu.entity.customer.ScoreHistory;
import com.xishu.entity.customer.VipLevel;
import com.xishu.entity.hardware.Printer;
import com.xishu.entity.oplog.OrderOpLog;
import com.xishu.entity.order.*;
import com.xishu.entity.plat.GlobalSetting;
import com.xishu.entity.shop.*;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.ResponseData;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.service.order.create.CreateOrderChain;
import com.xishu.service.order.create.DiscountChain;
import com.xishu.service.print.PrinterService;
import com.xishu.util.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import javax.persistence.Tuple;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;
import static com.xishu.response.ResponseStatus.*;

/**
 * 订单服务
 */
public class OrderService implements Tools {
    public static final String DOLA_ODER_NO = "/dola/oderNo/";


    private static Logger logger = LoggerFactory.getLogger(OrderService.class);

    private static OrderService instance = new OrderService();
    private CommonService commonService = CommonService.getInstance();
    private LockService localLockService = LockService.getInstance();
    private MappingService mappingService = MappingService.getInstance();
    private ItemService itemService = ItemService.getInstance();
    private ShopService shopService = ShopService.getInstance();
    private FoodTableService foodTableService = FoodTableService.getInstance();
    private SceneService sceneService = SceneService.getInstance();
    private Config config = Config.getInstance();

    private OrderService() {
    }

    public static OrderService getInstance() {
        return instance;
    }

    /**
     * 判断订单是否存在
     *
     * @param order
     * @return
     * @throws Exception
     */
    public boolean isExist(Order order) {
        try {
            //餐桌一定要存在
            FoodTable foodTable = foodTableService.findFoodTableByUniqueCode(order.getShopId(), order.getTableRow(), order.getTableColumn(), order.getUniqueCode());

            //默认餐桌如果不存在的时候，创建一个
            if (getInt(order.getUniqueCode()) == 0 && foodTable == null) {
                logger.info("will create default food table for order {}", order.getId());
                FoodTable defaultFoodTable = new FoodTable();
                defaultFoodTable.setUniqueCode(0);
                defaultFoodTable.setShopId(order.getShopId());
                defaultFoodTable.setRow(order.getTableRow());
                defaultFoodTable.setColumn(order.getTableColumn());
                defaultFoodTable.setRelateOrderId(order.getId());
                commonService.createObject(defaultFoodTable);
                foodTable = defaultFoodTable;
            }


            FoodTable finalFoodTable = foodTable;
            VerifyUtil.verify(() -> finalFoodTable != null, ResponseStatus.FOOD_TABLE_NOT_EXIST);

            order.setFoodTableKey(getFoodTableKey(order));
            order.setStatusArray(Constant.ORDER_PROCESSING_STATUS_LIST);
            if (getInt(order.getUniqueCode()) != 0) {
                List<Order> orderList = CommonService.getInstance().searchAll(order);
                logger.info("order List size is {}", orderList.size());
                return isNotEmpty(orderList);
            } else {
                List<Order> orderList = findOrderByTemplateKey(order.getShopId(), getFoodTableKey(order));
                //固定餐桌订单，有没有结束的订单，并且是父订单的，那么就是存在相应的订单了
                logger.info("order List size is {}", orderList.size());
                return orderList.stream().filter(p -> getInt(p.getStatus()) != ORDER_STATUS_END && p.getParentOrderId() == null).findFirst().isPresent();
            }
        } catch (Exception e) {
            logger.error("e", e);
            return true;
        }
    }

    /**
     * 查询堂食的订单是否存在
     *
     * @param shopId
     * @param row
     * @param uniqueCode
     * @return
     */
    public Order findOrder(Long shopId, Integer row, Integer column, Integer uniqueCode) throws Exception {
        Order order = new Order();
        order.setShopId(shopId);
        String foodTableKey = getFoodTableKey(row, column, uniqueCode);
        order.setFoodTableKey(foodTableKey);

        //不是餐桌二维码扫描的时候，才需要有场景值
        order.setUniqueCode(getInt(uniqueCode));
        Shop shop = ShopService.getInstance().findShopById(shopId);

        order.setStatusArray(Constant.ORDER_PROCESSING_STATUS_LIST);
        order.setStartCreateTime(shop.getOpenTime());
        return CommonService.getInstance().searchOne(order);
    }

    /**
     * 查询VIP订单,不做分表处理
     *
     * @param orderId
     * @return
     */
    public Order findOrder(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        return commonService.searchOne(order);
    }

    /**
     * 查询订单
     *
     * @param shopId
     * @param uniqueCode
     * @return
     */
    public Order findOrder(Long shopId, Integer uniqueCode) {
        Order order = new Order();
        order.setShopId(shopId);
        order.setUniqueCode(uniqueCode);
        return commonService.searchOne(order);
    }

    /**
     * 通过餐桌查找订单
     *
     * @param foodTable
     * @return
     */
    public Order findOrder(FoodTable foodTable) throws Exception {
        return findOrder(foodTable.getShopId(), foodTable.getRow(), foodTable.getColumn(), foodTable.getUniqueCode());
    }

    /**
     * 查询菜品在特定场景下面的价格
     *
     * @param itemId
     * @param sceneId
     * @return
     */
    public Double findOrderItemPriceByScene(Long itemId, Long sceneId) throws Exception {
        ItemService itemService = ItemService.getInstance();
        Item item = itemService.findItem(itemId);
        Optional<PriceConfig> priceConfigOptional = item.getPriceConfigList().stream().filter(p -> equals(p.getSceneId(), sceneId)).findAny();

        if (priceConfigOptional.isPresent()) {
            Double price = formatDouble(priceConfigOptional.get().getPrice());
            logger.info("find the price {}", price);
            return price;
        }

        //没有找到，那么看是否有固定价格
        //没有场景，则返回基础的价格，如果基础价格不对，则报错
        VerifyUtil.verify(() -> getDouble(item.getPrice()) > 0, ResponseStatus.ITEM_PRICE_NOT_CONFIG);
        logger.info("item is fix price {}", itemId);
        return formatDouble(item.getPrice());
    }

    /**
     * 获取端口的价格
     *
     * @param orderItem
     * @return
     */
    public Double findItemPrice(OrderItem orderItem, Order order) throws Exception {
        if (orderItem.getSceneId() != null && getLong(orderItem.getSceneId()) != 0) {
            logger.info("the scene id is {}", orderItem.getSceneId());
            //按照添加到购物车里面时的价格来计算
            return findOrderItemPriceByScene(orderItem.getItemId(), orderItem.getSceneId());
        } else {
            Optional<Scene> sceneOptional = SceneService.getInstance().findSceneOptional(order.getShopId());
            if (!sceneOptional.isPresent()) {
                logger.info("current time do not have scene shop id {} ", order.getShopId());
                VerifyUtil.throwError(ResponseStatus.ITEM_PRICE_NOT_CONFIG);
            }

            Long sceneId = sceneOptional.get().getId();
            logger.info("current scene id is {}", sceneId);
            return findOrderItemPriceByScene(orderItem.getItemId(), sceneId);
        }
    }

    /**
     * 计算额外的价格
     *
     * @param orderItem
     * @return
     */
    public Double calAdditionalPrice(OrderItem orderItem) throws Exception {
        Item itemInDb = ItemService.getInstance().findItem(orderItem.getItemId());

        List<ItemDetail> itemDetailList = orderItem.getItemDetailList();
        if (!getBoolean(itemInDb.getSetMenu())) {
            //没有额外的项
            if (isEmpty(orderItem.getItemDetailList())) {
                logger.info("order item detail is empty");
                return 0d;
            }

            Double price = itemService.calAdditionalPrice(itemInDb, itemDetailList);
            logger.info("normal item additional price is {}", price);
            return price;
        } else {
            //套餐的价格单独计算
            Double price = itemService.calSetMenuAdditionalPrice(itemInDb, orderItem);
            logger.info("set menu item addition price is {}", price);
            return price;
        }
    }

    /**
     * @param orderItem
     * @return
     */
    public OrderItem calItemPrice(OrderItem orderItem, Order orderInDb) throws Exception {
        //特别菜不做处理
        if (equals(orderItem.getItemId(), SPECIAL_ITEM)) {
            return orderItem;
        }

        Double baseItemPrice = findItemPrice(orderItem, orderInDb);
        Double additionalPrice = calAdditionalPrice(orderItem);

        OrderItem priceOrderItem = new OrderItem();
        priceOrderItem.setItemTotalCost(showMoneyDouble(baseItemPrice + additionalPrice));
        priceOrderItem.setItemPrice(showMoneyDouble(priceOrderItem.getItemTotalCost()));
        priceOrderItem.setBasePrice(showMoneyDouble(baseItemPrice));
        logger.info("cal item price end");
        return priceOrderItem;
    }

    /**
     * 餐桌KEY
     *
     * @param row
     * @param column
     * @param uniqueCode
     * @return
     */
    public String getFoodTableKey(Integer row, Integer column, Integer uniqueCode) throws Exception {
        Order order = new Order();
        order.setTableRow(row);
        order.setTableColumn(column);
        order.setUniqueCode(uniqueCode);
        return getFoodTableKey(order);
    }

    /**
     * 获取餐桌KEY
     *
     * @param order
     * @return
     */
    public String getFoodTableKey(Order order) throws Exception {
        VerifyUtil.verify(() -> order.getTableRow() != null && order.getTableColumn() != null && order.getUniqueCode() != null);
        StringBuffer stringBuffer = new StringBuffer();
        //行号：列号：唯一序列号
        return stringBuffer.append(order.getTableRow()).append(SEPARATOR_KEY).append(order.getTableColumn()).append(SEPARATOR_KEY).append(order.getUniqueCode()).toString();
    }

    /**
     * 通过餐桌获取餐桌码
     *
     * @param foodTable
     * @return
     */
    public String getFoodTableKey(FoodTable foodTable) {
        StringBuffer stringBuffer = new StringBuffer();
        return stringBuffer.append(foodTable.getRow()).append(SEPERATOR_KEY).append(foodTable.getColumn()).append(SEPERATOR_KEY).append(foodTable.getUniqueCode()).toString();
    }

    /**
     * 查询订单
     *
     * @param reqOrder
     */
    public Order findOrder(Order reqOrder) throws ResponseStatusException {
        VerifyUtil.verify(() -> reqOrder.id != null && reqOrder.getShopId() != null);
        Order order = new Order();
        order.setId(reqOrder.getId());
        order.setShopId(reqOrder.getShopId());
        Order orderInDb = commonService.searchOne(order);
        VerifyUtil.verify(() -> orderInDb != null);
        return orderInDb;
    }

    /**
     * 查询订单
     *
     * @param shopId
     * @param foodTableKey
     * @return
     */
    public Order findOrder(Long shopId, String foodTableKey) {
        Order order = new Order();
        order.setShopId(shopId);
        order.setFoodTableKey(foodTableKey);
        order.setStartCreateTime(System.currentTimeMillis() - DateUtil.ONE_DAY);
        List<Order> orderList = commonService.searchAll(order);
        if (isEmpty(orderList)) {
            return null;
        }

        return orderList.get(0);
    }

    /**
     * 菜品的规格是否保持一致
     *
     * @param orderItem1
     * @param orderItem2
     */
    public boolean equals(OrderItem orderItem1, OrderItem orderItem2) {
        if (orderItem1.getItemId().longValue() != orderItem2.getItemId().longValue()) {
            logger.info("item is not equals , will add new order item");
            return false;
        }

        //都没有规格
        if (isEmpty(orderItem1.getItemDetailList()) && isEmpty(orderItem2.getItemDetailList())) {
            logger.info("the same do not have the item detail list");
            return true;
        }

        //判断规格
        List<ItemDetail> itemDetailList1 = orderItem1.getItemDetailList();
        List<ItemDetail> itemDetailList2 = orderItem2.getItemDetailList();
        //规格数量不一致，不用处理
        if (itemDetailList1.size() != itemDetailList2.size()) {
            logger.info("list detail size is not same");
            return false;
        }

        //规格数量一致，每一个都要一致
        return itemDetailList1.stream().allMatch(p -> {
            return contains(itemDetailList2, p);
        });
    }

    /**
     * 商品详情列表是否包含了该详情
     *
     * @param itemDetailList
     * @param itemDetail
     * @return
     */
    public boolean contains(List<ItemDetail> itemDetailList, ItemDetail itemDetail) {
        if (isEmpty(itemDetailList)) {
            return false;
        }
        return itemDetailList.stream().filter(p -> Objects.equals(p, itemDetail)).findAny().isPresent();
    }



    /**
     * 查询订单
     *
     * @param shopId
     * @param orderId
     */
    public Order findOrder(Long shopId, Long orderId) throws Exception {
        return findOrder(shopId, orderId, true);
    }

    /**
     * 查询订单
     *
     * @param shopId
     * @param orderId
     * @param flagDeleteCanFind 已删除的订单也可以查询到
     * @return
     */
    public Order findOrder(Long shopId, Long orderId, boolean flagDeleteCanFind) throws Exception {
        VerifyUtil.verify(() -> shopId != null && orderId != null);
        long startTime = System.currentTimeMillis();
        Order order = new Order();
        order.setId(orderId);
        order.setShopId(shopId);

        Order orderInDb = commonService.findEntity(order);
        VerifyUtil.verify(() -> orderInDb != null);

        //需要检查标记删除
        if (!flagDeleteCanFind) {
            VerifyUtil.verify(() -> !getBoolean(orderInDb.getFlagDelete()), ORDER_DELETED);
        }

        //添加默认值
        if (orderInDb.getOrderItemDetailList() == null) {
            orderInDb.setOrderItemDetailList(new ArrayList<>());
        }

        if (orderInDb.getTicketCodeList() == null) {
            orderInDb.setTicketCodeList(new ArrayList<>());
        }

        logger.info("find the order cost time {}", System.currentTimeMillis() - startTime);

        upgradeSetMenuItemInOrder(orderInDb);

        commonService.dealDefaultValueWithAnnotation(orderInDb);

        return orderInDb;
    }

    /**
     * 查询订单
     *
     * @param shopId
     * @param orderId
     * @return
     * @throws ResponseStatusException
     */
    public Optional<Order> findOrderOptional(Long shopId, Long orderId) throws ResponseStatusException {
        VerifyUtil.verify(() -> shopId != null && orderId != null);
        Order order = new Order();
        order.setId(orderId);
        order.setShopId(shopId);
        Order orderInDb = commonService.searchOne(order);

        if (orderInDb == null) {
            return Optional.empty();
        } else {
            if (orderInDb.getOrderItemDetailList() == null) {
                orderInDb.setOrderItemDetailList(new ArrayList<>());
            }
            return Optional.of(orderInDb);
        }
    }

    /**
     * 直接从数据库里面查询出来数据，不更新现有内存里面的数据
     *
     * @param shopId
     * @param orderId
     * @return
     */
    public Order findOrderDirect(Long shopId, Long orderId) throws ResponseStatusException {
        VerifyUtil.verify(() -> shopId != null && orderId != null);
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Order order = orderDao.findOrder(shopId, orderId);

        if (order == null) {
            throw new ResponseStatusException(ResponseStatus.INVALID_PARAMETER);
        }

        commonService.dealFieldMapping(order, false);
        return order;
    }

    /**
     * 查询订单，已经被删除的订单也可以查询出来
     *
     * @param shopId
     * @param orderId
     * @return
     */
    public Order findOrderCanFlagDelete(Long shopId, Long orderId) throws ResponseStatusException {
        VerifyUtil.verify(() -> shopId != null && orderId != null);
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Order orderInDb = orderDao.findOrder(shopId, orderId);
        //删除是否存在
        VerifyUtil.verify(() -> orderInDb != null);
        commonService.dealFieldMapping(orderInDb, false);
        return orderInDb;
    }

    /**
     * 查询订单
     *
     * @param order
     * @return
     * @throws ResponseStatusException
     */
    public Order findOrderCanFlagDelete(Order order) throws ResponseStatusException {
        return findOrderCanFlagDelete(order.getShopId(), order.getId());
    }

    /**
     * 订单的锁ID
     *
     * @param order
     * @return
     */
    public String getLockKey(Order order) throws ResponseStatusException {
        VerifyUtil.verify(() -> order.id != null && order.getShopId() != null);
        StringBuilder stringBuilder = new StringBuilder();
        return stringBuilder.append(order.getShopId()).append(":").append(order.id).toString();
    }

    /**
     * 订单的锁ID
     *
     * @return
     */
    public String getLockKey(Long shopId, Long orderId) {
        StringBuilder stringBuilder = new StringBuilder();
        return stringBuilder.append(shopId).append(":").append(orderId).toString();
    }

    /**
     * 外卖订单的聚餐码的锁
     *
     * @param shopId
     * @return
     */
    public String getTakeOutLockKey(Long shopId) {
        StringBuffer sb = new StringBuffer();
        return sb.append(shopId).append(SEPARATOR_KEY).append("take.out").toString();
    }

    /**
     * 外卖订单的聚餐码
     *
     * @param shopId
     * @return
     */
    public String getTakeOutZkPath(Long shopId) {
        StringBuffer sb = new StringBuffer();
        return sb.append("/dola/shop/takeout/").append(shopId).toString();
    }

    /**
     * 客户更新订单状态
     *
     * @param status
     * @param orderInDb
     * @return
     */
    public ResponseData customerChangeOrderStatus(int status, Order orderInDb) throws Exception {
        //没有设置过，则设置一下
        orderInDb.setStatus(status);
        logger.info("will set order status to {}", status);
        commonService.save(orderInDb);
        return commonService.createResponse(orderInDb);
    }

    /**
     * 创建一个子订单，用于支付的时候用，特别是分菜结账以及分钱结账
     *
     * @param order
     * @return
     */
    public Order createPayOrder(Order order) throws Exception {
        //创建子订单或者支付订单的时候，订单均不能是被删除的状态
        VerifyUtil.verify(() -> !getBoolean(order.getFlagDelete()), ORDER_DELETED);

        Order newOrder = new Order();

        //如果是外卖平台的订单不校验
        if (!isTakeOutPlatOrder(order)) {
            //创建支付订单的时候，一定要是未支付状态
            VerifyUtil.verify(() -> !getBoolean(order.getPayed()), ResponseStatus.OTHER_USER_OPERATE_THE_ORDER);
        }

        BeanUtils.copyProperties(order, newOrder);
        newOrder.setId(null);

        if (getBoolean(order.getSubOrder())) {
            newOrder.setParentOrderId(order.getParentOrderId());
            newOrder.setRelatedSubOrderId(order.getId());
            newOrder.setSubOrderId(order.getSubOrderId());
        } else {
            newOrder.setParentOrderId(order.getId());
            newOrder.setSubOrderId(null);
        }

        String sessionId = ServletUtil.getSessionId();
        newOrder.setLastOperateSession(sessionId);
        newOrder.setStatus(ORDER_STATUS_PENDING_PAY);
        newOrder.setCreateTime(System.currentTimeMillis());
        newOrder.setRequestId(null);
        newOrder.setParentOrder(false);
        newOrder.setReturnCash(false);
        //支付订单只有在支付完成的时候，才会显示
        newOrder.setBusinessEndShow(false);
        newOrder.setFoodTableKey(null);
        newOrder.setReturnCash(false);
        newOrder.setPayed(false);
        newOrder.setDiscountFee(null);
        //添加消费税
        newOrder.setConsumptionTax(order.getConsumptionTax());
        Long userId = ServletUtil.getUserId();
        //没有用户ID,那么就是C端的订单
        newOrder.setCustomerPayOrder(userId == null);

        //如果是C端，那么将sessionId填写进去，以方便解锁
        newOrder.setSessionId(sessionId);

        //支付订单一开始都是空的优惠券列表，由前端请求带过来，如果有优惠
        newOrder.setTicketCodeList(new ArrayList<>());

        newOrder.setParentTicketCodeList(new ArrayList<>());
        newOrder.setSubOrder(false);
        newOrder.setCashPayList(null);
        newOrder.setCashPayJson(null);

        //过滤对应的菜，如果是B端，那么是checkout and confirm,如果是C端，那么只要是checkout就可以了
        if (ServletUtil.getUserId() == null) {
            List<OrderItem> orderItemListInC = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
            newOrder.setOrderItemDetailList(orderItemListInC);
        } else {
            List<OrderItem> orderItemListInB = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList());
            newOrder.setOrderItemDetailList(orderItemListInB);
        }

        return newOrder;
    }

    /**
     * 通过父ID查询订单列表
     *
     * @param parentId
     * @return
     */
    public List<Order> findOrderByParentId(Long parentId, Long shopId) {
        Order order = new Order();
        order.setParentOrderId(parentId);
        order.setShopId(shopId);
        return commonService.searchAll(order);
    }

    /**
     * 通过ID列表过滤菜品
     *
     * @param orderItemList
     * @param itemIdList
     * @return
     */
    public List<OrderItem> filterOrderItem(List<OrderItem> orderItemList, List<Long> itemIdList) {
        return orderItemList.stream().filter(p -> itemIdList.contains(p.getItemId().longValue())).collect(Collectors.toList());
    }

    /**
     * 过滤出订单里面菜
     *
     * @param orderInDb
     * @param orderItemList
     * @return
     */
    public List<OrderItem> filterOrderItem(Order orderInDb, List<OrderItem> orderItemList) {
        if (isEmpty(orderItemList)) {
            return new ArrayList<>();
        }

        List<Long> orderItemIdList = getList(orderItemList).stream().map(p -> p.getId()).collect(Collectors.toList());
        return filterOrderItemList(orderInDb, orderItemIdList);
    }

    /**
     * 计算价格，传进来的菜是什么就是什么，里面不做过滤
     *
     * @param order
     * @return
     */
    public PriceResult calPriceFilterOrderItem(Order order) throws Exception {
        return calPrice(order, false, true, true);
    }

    /**
     * 计算订单价格，默认不分钱
     *
     * @param order
     * @return
     * @throws Exception
     */
    public PriceResult calPrice(Order order) throws Exception {
        return calPrice(order, false);
    }

    /**
     * 计算订单的价格
     *
     * @param order
     * @param parCash
     * @return
     * @throws Exception
     */
    public PriceResult calPrice(Order order, boolean parCash) throws Exception {
        return calPrice(order, parCash, true, false);
    }


    /**
     * 计算一个订单的价格
     *
     * @param order
     * @param partCash 自定义金额这种会传金额过来计算
     * @return
     */
    public PriceResult calPrice(Order order, boolean partCash, Boolean filterCheckoutItem, Boolean alreadyFilterOrderItem) throws Exception {
        calCostOrigin(order, partCash, filterCheckoutItem, alreadyFilterOrderItem);
        double price = getDouble(order.getCostOrigin());
        //计算小计按比例配置的打包费
        packageFeeCompute(order);

        //计算服务费
        Shop shop = shopService.findShopById(order.getShopId());

        Double serviceFee = calServiceFee(order, partCash, calServiceOriginFee(order));

        logger.info("service fee is {}", serviceFee);
        order.setServiceFee(serviceFee);

        PriceResult priceResult = new PriceResult();
        if (serviceFee >= 0) {
            priceResult.setServiceFee(serviceFee);
        } else {
            priceResult.setServiceFee(0d);
        }

        Double cutCost = new DiscountChain().calDiscountFee(order, price, priceResult);
//        Double cutCost = calDiscountFee(order, price, priceResult);

        //最终价格，需要打折
        logger.info("price is {}, cutCost is {}, getServiceFee is {}, payOrderCost is {}, real discount fee {}", price, cutCost, order.getServiceFee(), order.getPayOrderCost(), order.getRealDiscountFee());

        //营业额
        double businessFee = price + order.getServiceFee() + showMoneyDouble(order.getPackageFee());

        if (getDouble(order.getDiscountFee()) > businessFee) {
            order.setRealDiscountFee(businessFee);
        } else {
            order.setRealDiscountFee(showMoneyDouble(order.getDiscountFee()));
        }

        price = price - cutCost;

        if (price <= 0) {
            logger.info("price {} will set to 0", price);
            price = 0d;
        }

        //计算消费税
        calConsumptionTax(order, shop, price, partCash);
        logger.info("order consumption tax fee {}", order.getConsumptionTax());

        //再添加消费税，如果已经是分钱结账，不用加消费税了
        if (!partCash || getInt(order.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_FOOD) {
            price = price + showMoneyDouble(order.getConsumptionTax());
        }

        //添加消费税
        price = price + order.getServiceFee();

        //添加打包费
        if (order.getPackageFee() != null) {
            logger.info("will add package fee {}", order.getPackageFee());
            price = price + order.getPackageFee();
        }

        //计算三种百分比的小费
        calTips(price, order);

        //如果传了小费过来，添加小费
        if (getDouble(order.getTipsFee()) > 0) {
            price = price + order.getTipsFee();
        }

        logger.info("before format money is {}", price);
        if (price <= 0) {
            price = 0d;
        }

        order.setLeftCash(price);
        order.setUserCost(showMoneyDouble(price));
        logger.info("after format money is {}", showMoneyDouble(price));
        priceResult.setDiscountFee(showDouble(order.getDiscountFee()));
        priceResult.setRealDiscountFee(showMoneyDouble(order.getRealDiscountFee()));

        if (showMoneyDouble(price) >= 0) {
            priceResult.setPrice(showMoneyDouble(price));
        } else {
            priceResult.setPrice(0d);
        }

        priceResult.setConsumptionTax(showMoneyDouble(order.getConsumptionTax()));

//        Long userId = ServletUtil.getUserId();
//        if (userId != null && isNotEmpty(order.getTicketCodeList()) && getBoolean(order.getParentOrder())) {
//            Order orderInDb = findOrder(order.getShopId(), order.getId());
//            //加锁
//            orderInDb.setLockByWaiter(true);
//            commonService.save(orderInDb);
//        }

        priceResult.setCalTipsList(order.getCalTipsList());
        priceResult.setTipsFee(order.getTipsFee());
        return priceResult;
    }

    /**
     * 计算小费
     *
     * @param price
     */
    public void calTips(double price, Order order) {
        //美国版本才计算小费的百分比
        if (config.isUsVersion()) {
            List<CalTips> calTipList = new ArrayList<CalTips>();

            //计算每个百分比对应的金额
            for (Integer percent : Arrays.asList(10, 15, 20)) {
                CalTips calTips = new CalTips();
                calTips.setPercent(percent);
                calTips.setTips(showTips((price * percent) / 100));
                calTips.setUserCost(showTips(price + calTips.getTips()));
                calTipList.add(calTips);
            }

            order.setCalTipsList(calTipList);
        }
    }

    /**
     * 小计-外卖折扣-优惠+销售税+服务费
     * <p>
     * 计算消费税
     *
     * @param order
     * @param shop
     * @param price
     */
    private void calConsumptionTax(Order order, Shop shop, Double price, boolean partCash) {
        String feCalPrice = ThreadContext.get(THREAD_LOCAL_VARIABLE_FE_CAL_PRICE);
        if (isNotEmpty(feCalPrice)) {
            logger.info("its fe cal price");
            return;
        }

        if (partCash) {
            logger.info("part cash , no need to cal consumption tax");
            return;
        }

        //只有美国版本才计算消费税
        if (config.isUsVersion()) {
            //计算消费税
            Double consumptionTax = getDouble(shop.getShopConfig().getConsumptionTax());
            logger.info("will cal consumption tax {}", consumptionTax);
            if (consumptionTax > 0) {
                order.setConsumptionTax(showMoneyDouble(consumptionTax / 100d * getDouble(price)));
                logger.info("consumption tax is {}", order.getConsumptionTax());
            }
        }
    }

    /**
     * 计算服务费
     *
     * @param order
     * @param partCash
     * @param price
     * @return
     */
    private Double calServiceFee(Order order, boolean partCash, double price) throws Exception {
        String feCalPrice = ThreadContext.get(THREAD_LOCAL_VARIABLE_FE_CAL_PRICE);
        if (isNotEmpty(feCalPrice)) {
            logger.info("fe cal price and sub order");
            return getDouble(order.getServiceFee());
        }


        Double serviceFee = 0d;

        //直接输入金额的都不算小费
        //分钱结账的小钱在前面的界面上会算一次
        if (!partCash) {
            //一个人结账以及分菜结账需要计算服务费
            //外卖单不收服务费
            if (getInt(order.getOrderType()) != ORDER_TYPE_TAKE_OUT && getInt(order.getOrderType()) != ORDER_TYPE_TAKE_OUT_PLAT) {
                Long sceneId = getOrderSceneId(order);
                Scene scene = SceneService.getInstance().findScene(sceneId);

                if (scene == null) {
                    logger.info("can find the sceneId {}");
                    return 0d;
                }

                logger.info("scene service fee percent {}", scene.getServiceFeePercent());

                //香港版本有特殊的取整方式
                if (config.isHkVersion()) {
                    BigDecimal b = BigDecimal.valueOf(getDouble(scene.getServiceFeePercent()) / 100d * price);

                    if (scene.getServiceRound().intValue() == SERVICE_FEE_ROUND_DOWN) {
                        serviceFee = b.setScale(0, BigDecimal.ROUND_FLOOR).doubleValue();
                    } else if (scene.getServiceRound().intValue() == SERVICE_FEE_ROUND) {
                        serviceFee = b.setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
                    } else if (scene.getServiceRound().intValue() == SERVICE_FEE_ROUND_UP) {
                        serviceFee = b.setScale(0, BigDecimal.ROUND_CEILING).doubleValue();
                    } else {
                        serviceFee = b.setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                } else {
                    BigDecimal b = BigDecimal.valueOf(scene.getServiceFeePercent() / 100d * price);
                    serviceFee = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                }
            } else {
                logger.info("take out order do not cal service fee");
            }
        }

        return serviceFee;
    }

    /**
     * 获取外卖订单里面的原始价格
     *
     * @param order
     * @return
     */
    private Double calTakeOutOriginFee(Order order) {
        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());

        return orderItemList.stream().filter(p -> {
            return !getBoolean(p.getExcludeTakeOutDiscount());
        }).mapToDouble(p -> p.getItemPrice() * p.getCount()).sum();
    }

    /**
     * 计算服务费的小计
     *
     * @param order
     * @return
     */
    private Double calServiceOriginFee(Order order) {
        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());

        double sum = orderItemList.stream().filter(p -> {
            return !getBoolean(p.getExcludeServiceFee());
        }).mapToDouble(p -> p.getItemPrice() * p.getCount()).sum();

        logger.info("service origin fee is {}", sum);

        return sum >= 0 ? sum : 0;
    }

    /**
     * 计算打折比例
     * <p>
     * 如果有菜不参与打折，那么比例将会小于100%
     *
     * @param order
     * @return
     */
    private Double calDiscountPercent(Order order) {
        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());

        if (isEmpty(orderItemList)) {
            logger.info("order item list is empty");
            return 1.0;
        }

        double discountItemSumPrice = orderItemList.stream().filter(p -> {
            return !getBoolean(p.getExcludeDiscountTicket());
        }).mapToDouble(p -> p.getItemPrice() * p.getCount()).sum();

        if (discountItemSumPrice == 0) {
            logger.info("no order item satisfy discount ticket");
        }

        double orderItemSumPrice = orderItemList.stream().mapToDouble(p -> p.getItemPrice() * p.getCount()).sum();
        return discountItemSumPrice / orderItemSumPrice;
    }

    /**
     * 计算小计费用
     *
     * @param order
     * @param partCash
     * @return
     * @throws ResponseStatusException
     */
    private void calCostOrigin(Order order, boolean partCash, Boolean filterCheckoutItem, Boolean alreadyFilterOrderItem) throws ResponseStatusException {
        logger.info("cal cost origin , order id  is {}, partCash is {}, filterCheckoutItem {}, alreadyFilterOrderItem {} ", order.getId(), partCash, filterCheckoutItem, alreadyFilterOrderItem);
        String feCalPrice = ThreadContext.get(THREAD_LOCAL_VARIABLE_FE_CAL_PRICE);
        if (isNotEmpty(feCalPrice)) {
            logger.info("fe cal price and in sub order");
            return;
        }

        List<OrderItem> orderItemList = null;

        if (alreadyFilterOrderItem) {
            orderItemList = order.getOrderItemDetailList();
        } else {
            orderItemList = filterOrderItemList(order, filterCheckoutItem);
        }

        double price = 0;
        if (isNotEmpty(orderItemList) && !partCash) {
            logger.info("not dependsCash cal price");
            //分菜结账，每个菜品的总价也重新计算下
            for (OrderItem orderItem : orderItemList) {
                orderItem.setItemTotalCost(getDouble(orderItem.getItemPrice()) * orderItem.getCount());
            }

            price = orderItemList.stream().mapToDouble(p -> p.getItemPrice() * p.getCount()).sum();
            logger.info("the price is {}", price);
            price = formatMoneyDouble(price);
            //同时设置订单的价格,用户未付款的价格
            logger.info("the price is {}", price);
            if (price < 0) {
                price = 0d;
            }

            order.setCostOrigin(price);
            order.setLeftCash(price);
        } else if (partCash) {
            logger.info("part pay, user cost is {}", order.getUserCost());
            //分钱结账
            VerifyUtil.verify(() -> order.getUserCost() != null);
            price = formatDouble(order.getUserCost());
            order.setCostOrigin(price);
            order.setLeftCash(price);
        } else {
            logger.info("its empty");
            //购物车里面为空，需要把钱全部清空
            order.setCostOrigin(0d);
            order.setLeftCash(0d);
            order.setUserCost(0d);
            order.setServiceFee(0d);
            order.setPackageFee(0d);
        }

        logger.info("calCostOrigin end");
    }

    /**
     * 过滤菜品列表
     *
     * @param order
     * @param filterCheckoutItem
     * @return
     */
    public List<OrderItem> filterOrderItemList(Order order, Boolean filterCheckoutItem) {
        List<OrderItem> orderItemList = null;
        if (getBoolean(filterCheckoutItem)) {
            logger.info("will filterCheckoutItem");
            orderItemList = getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());

            if (ServletUtil.isBEndPayOrder()) {
                orderItemList = orderItemList.stream().filter(p -> getBoolean(p.getConfirmItem())).collect(Collectors.toList());
            }

        } else {
            logger.info("user the order data");
            orderItemList = getList(order.getOrderItemDetailList());
        }

        return orderItemList;
    }

    /**
     * 通过订单查询公司的ID
     *
     * @param order
     * @return
     */
    public Long findCompanyId(Order order) throws Exception {
        Long shopId = order.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return shop.getCompanyId();
    }

    /**
     * 计算打折费用
     *
     * @param order
     * @param price
     * @param priceResult
     * @return
     */
    private Double calDiscountFee(Order order, double price, PriceResult priceResult) throws Exception {
        Long customerId = order.getCustomerId();
        List<DiscountTicket> discountTicketList = new ArrayList<>();
        Long companyId = findCompanyId(order);
        Long userId = ServletUtil.getUserId();

        //是否已经成功添加了打折卷
        boolean addDiscountTicket = false;
        //已经添加了一张优惠券
        boolean checkOneTicketAlready = false;
        //只有一张优惠券可以使用
        boolean onlyOneTicketCanUse = false;
        Set<String> sameCodeList = new HashSet<>();

        //如果有优惠卷的,计算优惠卷
        if (isNotEmpty(order.getTicketCodeList())) {
            for (String code : order.getTicketCodeList()) {
                DiscountTicket discountTicket = DiscountTicketService.getInstance().findTicketByCode(code, companyId);

                //优惠卷不存在
                if (discountTicket == null) {
                    logger.info("{} do not find", code);
                    priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_NOT_EXIST));
                    continue;
                }

                Optional<CustomerTicket> customerTicketOptional = CustomerService.getInstance().findCustomerTicketInCompany(companyId, code);

                if (userId == null) {
                    if (customerId == null) {
                        //匿名用户不能使用已经被绑定的CODE
                        if (customerTicketOptional.isPresent()) {
                            logger.info("{} bind by others", discountTicket.getCode());
                            priceResult.getResultList().add(new TicketResult(code, TICKET_EXCHANGE_BY_OTHERS));
                            continue;
                        }
                    } else {
                        if (customerTicketOptional.isPresent()) {
                            //会员账号，不能使用被其它账号绑定的CODE
                            CustomerTicket customerTicket = customerTicketOptional.get();
                            boolean sameUser = equals(customerTicket.getCustomerId(), customerId);
                            if (!sameUser) {
                                logger.info("{} bind by others", discountTicket.getCode());
                                priceResult.getResultList().add(new TicketResult(code, TICKET_EXCHANGE_BY_OTHERS));
                                continue;
                            }
                        }
                    }
                }

                //不是店长优惠券才需要判断（堂食，外卖），（商铺ID是否匹配），（有效期），（场景）,(是否已经使用)
                if (!DiscountTicketService.getInstance().isWaiterLeaderTicket(discountTicket)) {
                    //优惠卷已使用
                    if (getBoolean(discountTicket.getUsed())) {
                        logger.info("ticket used {}", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_NOT_EXIST));
                        continue;
                    }

                    //判断堂食是否可以使用
                    List<Integer> tangShiList = Arrays.asList(ORDER_TYPE_QUICK_FOOD, ORDER_TYPE_TANG_SHI);
                    Integer orderType = order.getOrderType();
                    boolean tangShiOrder = tangShiList.stream().filter(p -> equals(p, orderType)).findAny().isPresent();
                    if (tangShiOrder && !getBoolean(discountTicket.getTangshi())) {
                        logger.info("{} take out not match", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_FOR_TAKE_OUT));
                        continue;
                    }

                    //外卖订单，但是优惠券又不可以使用外卖
                    if (!tangShiOrder && !getBoolean(discountTicket.getTakeout())) {
                        logger.info("{} tangshi not match", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_FOR_TANGSHI));
                        continue;
                    }

                    //优惠卷对应的商铺ID不匹配
                    boolean shopMatch = discountTicket.getShopList().stream().anyMatch(p -> p.getId().longValue() == order.getShopId().longValue());
                    if (!shopMatch) {
                        logger.info("{} shop do not match", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_NOT_EXIST));
                        continue;
                    }

                    //有效期要匹配上
                    long currentTimeMillis = System.currentTimeMillis();
                    if (!(currentTimeMillis >= discountTicket.getStartTime() && currentTimeMillis <= discountTicket.getEndTime())) {
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_EXPIRED));
                        continue;
                    }

                    //时间要匹配上
                    boolean timeMatch = discountTicket.getSceneList().stream().map(p -> {
                        try {
                            Scene scene = sceneService.findScene(p.getId());
                            return scene;
                        } catch (Exception e) {
                            logger.info("{} do not find", discountTicket.getCode());
                            logger.error("e", e);
                            priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_NOT_EXIST));
                            return null;
                        }
                    }).anyMatch(p -> {
                        List<SceneTimeConfig> timeConfigList = p.getTimeConfigList();
                        return timeConfigList.stream().anyMatch(t -> sceneService.isMatchTimeConfig(t));
                    });

                    if (!timeMatch) {
                        logger.info("{} time not match", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_TIME_NOT_MATCH));
                        continue;
                    }
                }

                //优惠卷的门槛要匹配上
                Double atLeastCost = getDouble(discountTicket.getAtLeastCost());
                if (price < atLeastCost) {
                    logger.info("{} do not match the at least cost", discountTicket.getCode());
                    priceResult.getResultList().add(new TicketResult(code, ResponseStatus.DISCOUNT_TICKET_NOT_MATCH_AT_LEAST_COST));
                    continue;
                }

                //已经添加过了打折卷，又再次添加打折卷
                if (addDiscountTicket && getInt(discountTicket.getTicketType()) == DISCOUNT_TICKET_TYPE_DISCOUNT) {
                    logger.info("{} has one discount ticket", discountTicket.getCode());
                    priceResult.getResultList().add(new TicketResult(code, ResponseStatus.ONLY_ONE_DISCOUNT_TICKET));
                    continue;
                }

                if (sameCodeList.contains(discountTicket.getCode())) {
                    logger.info("{} same ticket in order", discountTicket.getCode());
                    priceResult.getResultList().add(new TicketResult(discountTicket.getCode(), SAME_TICKET_IN_ONE_ORDER));
                    continue;
                }

                //如果有相同的优惠卷，那么给提示
                sameCodeList.add(discountTicket.getCode());

                if (getInt(discountTicket.getTicketType()) == DISCOUNT_TICKET_TYPE_DISCOUNT) {
                    addDiscountTicket = true;
                }

                //如果是菜品券，那么添加菜品券的判断
                if (getBoolean(discountTicket.getItemTicket())) {
                    //判断该订单里面的菜是否在菜品券的范围里面
                    List<Long> mainItemIdListInTicket = discountTicket.getMainItemIdList();
                    List<Long> mainItemIdListInOrder = getMainItemIdListFromOrder(order);
                    Collection intersection = CollectionUtils.intersection(mainItemIdListInTicket, mainItemIdListInOrder);

                    if (isEmpty(intersection)) {
                        logger.info("{} order item not match", discountTicket.getCode());
                        priceResult.getResultList().add(new TicketResult(discountTicket.getCode(), ORDER_ITEM_NOT_MATCH_TICKET));
                        continue;
                    }
                }

                if (onlyOneTicketCanUse) {
                    logger.info("{} can not mutli used", discountTicket.getCode());
                    priceResult.getResultList().add(new TicketResult(discountTicket.getCode(), ResponseStatus.DISCOUNT_TICKET_CAN_USE_ONCE));
                    continue;
                }

                //已经添加了一张优惠券，新添加的优惠券不能多张使用
                if (checkOneTicketAlready && !getBoolean(discountTicket.getMultiUsed())) {
                    logger.info("{} can not mutli used", discountTicket.getCode());
                    priceResult.getResultList().add(new TicketResult(discountTicket.getCode(), ResponseStatus.DISCOUNT_TICKET_CAN_USE_ONCE));
                    continue;
                }

                //已经成功添加了一张
                checkOneTicketAlready = true;

                if (!getBoolean(discountTicket.getMultiUsed())) {
                    onlyOneTicketCanUse = true;
                }

                //条件满足的优惠卷
                discountTicketList.add(discountTicket);
            }
        }

        if (isNotEmpty(discountTicketList)) {
            //如果存在只有一张才能使用的优惠卷，但是又有多张
            if (order.getTicketCodeList().size() > 1) {
                List<DiscountTicket> oneUsedTicketList = discountTicketList.stream().filter(p -> !getBoolean(p.getMultiUsed())).collect(Collectors.toList());
                for (DiscountTicket ticket : oneUsedTicketList) {
                    priceResult.getResultList().add(new TicketResult(ticket.getCode(), ResponseStatus.DISCOUNT_TICKET_CAN_USE_ONCE));
                    continue;
                }
            }
        }

        logger.info("the cal cut cost the price is {}", price);
        priceResult.setCostOrigin(price);

        //resultList是上面添加的错误列表
        List<TicketResult> resultList = priceResult.getResultList();

        //过滤出没有问题的优惠卷，然后写计算价格，以及对应的描述
        if (isNotEmpty(order.getTicketCodeList())) {
            List<String> errorCodeList = resultList.stream().map(p -> p.getCode()).collect(Collectors.toList());

            List<String> rightCodeList = order.getTicketCodeList().stream().filter(p -> !errorCodeList.contains(p)).collect(Collectors.toList());
            for (String ticketCode : rightCodeList) {
                resultList.add(new TicketResult(ticketCode, DiscountTicketService.getInstance().findTicketByCode(ticketCode, companyId)));
            }

            //如果仅仅是相同的优惠卷，那么需要添加一个可用的进来
            Set<String> sameCodeListTmp = resultList.stream().filter(p -> equals(p.getStatus(), SAME_TICKET_IN_ONE_ORDER.getStatus())).map(p -> p.getCode()).collect(Collectors.toSet());
            for (String ticketCode : sameCodeListTmp) {
                resultList.add(new TicketResult(ticketCode, DiscountTicketService.getInstance().findTicketByCode(ticketCode, companyId)));
            }
        }

        List<TicketResult> rightTicketResult = priceResult.getResultList().stream().filter(p -> getInt(p.getStatus()) == 0).collect(Collectors.toList());

        Double cutCost = 0d;
        order.setTakeOutDiscountFee(null);

        if (getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT) {
            Double takeOutOriginPrice = calTakeOutOriginFee(order);
            Long sceneId = getOrderSceneId(order);
            Scene scene = SceneService.getInstance().findScene(sceneId);
            if (scene != null) {
                //如果店铺设置了外卖打折，并且当前订单也是外卖单，那么打折
                Double takeoutFeePercent = scene.getTakeoutFeePercent();
                logger.info("will cut take out fee percent {}", takeoutFeePercent);

                //必须大于等于0
                if (getDouble(takeoutFeePercent) > 0) {
                    //7.5折，那么就是折扣0。25
                    double percent = (10 - takeoutFeePercent) / 10d;
                    logger.info("take out cut percent is {}", percent);
                    cutCost = showInteger(takeOutOriginPrice * percent);
                    logger.info("take out cut cost is {}", showDouble(cutCost));

                    if (cutCost <= 0) {
                        logger.info("reset the cut cost to 0");
                        cutCost = 0d;
                    }

                    order.setTakeOutDiscountFee(showInteger(cutCost));
                } else {
                    logger.info("some take out fee percent error");
                }
            }
        }

        List<TicketDiscountFee> ticketDiscountFeeList = new ArrayList<>();

        Double discountFee = 0d;
        //如果优惠卷都没有问题，然后减去优惠卷的金额
        if (isNotEmpty(rightTicketResult)) {
            Order cloneOrder = (Order) ClassUtil.clone(order);

            List<String> codeList = rightTicketResult.stream().map(p -> p.getCode()).collect(Collectors.toList());
            //过滤出可用的优惠卷
            discountTicketList = discountTicketList.stream().filter(p -> codeList.contains(p.getCode())).collect(Collectors.toList());

            //求减去的金额的总和
            for (DiscountTicket ticket : discountTicketList) {
                //这里判断优惠卷是否满足门槛，小计优惠后再处理，如果不满足门槛，则添加到返回的列表里面，同时不优惠
                if (price < getDouble(ticket.getAtLeastCost())) {
                    List<TicketResult> ticketResults = priceResult.getResultList().stream().filter(p -> !equals(p.getCode(), ticket.getCode())).collect(Collectors.toList());
                    priceResult.setResultList(ticketResults);
                    priceResult.getResultList().add(new TicketResult(ticket.getCode(), ResponseStatus.DISCOUNT_TICKET_NOT_MATCH_AT_LEAST_COST));
                    continue;
                }

                //添加菜品券的处理
                if (getBoolean(ticket.getItemTicket())) {
                    //单个菜品有效
                    if (!getBoolean(ticket.getMultiItemValid())) {
                        List<OrderItem> filterOrderItemList = filterOrderItemInDiscount(cloneOrder, ticket);

                        //券对应的菜已经都打了折扣了
                        if (isEmpty(filterOrderItemList)) {
                            continue;
                        }

                        //最低价格的菜,最低价格的菜，减少的金额不能超过本身的价格
                        Long lowestPriceOrderItemId = filterLowestPriceOrderItem(filterOrderItemList);
                        OrderItem orderItem = filterOrderItemList(cloneOrder, lowestPriceOrderItemId);
                        Double itemTicketCutFee = 0d;

                        addOrderItemDiscount(orderItem, 1);

                        //免单券
                        if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_FREE_ITEM) {
                            logger.info("item free ticket {}", orderItem.getBasePrice());
                            itemTicketCutFee = orderItem.getBasePrice();
                        } else if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_CASH && getDouble(ticket.getDiscountCash()) > 0) {
                            //满减券
                            //菜的价格比减少的钱更小，以菜的价格为准
                            itemTicketCutFee = Math.min(getDouble(orderItem.getBasePrice()), ticket.getDiscountCash());
                        } else if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_DISCOUNT && getDouble(ticket.getDiscount()) > 0) {
                            //折扣券
                            logger.info("discount ticket {}", orderItem);
                            itemTicketCutFee = orderItem.getBasePrice() * getDiscount(ticket);
                        }

                        //香港版本取整，美国版本取小数点后两位
                        itemTicketCutFee = showInteger(itemTicketCutFee).doubleValue();

                        //减去菜品的金额
                        discountFee = discountFee + itemTicketCutFee;
                        cutCost = cutCost + itemTicketCutFee;
                        price = price - itemTicketCutFee;
                        addTicketDiscountFeePrice(ticketDiscountFeeList, ticket.getCode(), itemTicketCutFee);
                    } else {
                        //多个菜品有效
                        //先过滤出相关的菜
                        List<OrderItem> filterOrderItemList = filterOrderItemInDiscount(cloneOrder, ticket);
                        Double itemTicketCutFee = 0d;

                        //免单券
                        if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_FREE_ITEM) {
                            itemTicketCutFee = filterOrderItemList.stream().mapToDouble(orderItem -> orderItem.getBasePrice() * (orderItem.getCount() - orderItem.getDiscountNumber())).sum();
                        } else if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_CASH && getDouble(ticket.getDiscountCash()) > 0) {
                            //满减券
                            //菜的价格比减少的钱更小，以菜的价格为准
                            double tmpCutFee = filterOrderItemList.stream().mapToDouble(orderItem -> {
                                return Math.min(ticket.getDiscountCash(), orderItem.getBasePrice()) * (orderItem.getCount() - orderItem.getDiscountNumber());
                            }).sum();

                            itemTicketCutFee = tmpCutFee;
                        } else if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_DISCOUNT && getDouble(ticket.getDiscount()) > 0) {
                            //折扣券
                            itemTicketCutFee = filterOrderItemList.stream().mapToDouble(orderItem -> orderItem.getBasePrice() * (orderItem.getCount() - orderItem.getDiscountNumber())).sum() * getDiscount(ticket);
                        }

                        //设置折扣数量
                        for (OrderItem orderItem : filterOrderItemList) {
                            orderItem.setDiscountNumber(orderItem.getCount());
                        }

                        //香港版本取整，美国版本取小数点后两位
                        itemTicketCutFee = showInteger(itemTicketCutFee).doubleValue();

                        //减去菜品的金额
                        discountFee = discountFee + itemTicketCutFee;
                        cutCost = cutCost + itemTicketCutFee;
                        price = price - itemTicketCutFee;

                        addTicketDiscountFeePrice(ticketDiscountFeeList, ticket.getCode(), itemTicketCutFee);
                    }

                    continue;
                }

                if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_DISCOUNT && getDouble(ticket.getDiscount()) > 0) {
                    logger.info("will cut discount {}", ticket.getDiscount());
                    Double itemDiscountPercent = calDiscountPercent(order);
                    double ticketDiscountFee = showInteger(price * (1 - ticket.getDiscount() / 10d) * itemDiscountPercent).doubleValue();
                    discountFee = discountFee + ticketDiscountFee;
                    cutCost = cutCost + ticketDiscountFee;
                    price = price - ticketDiscountFee;

                    addTicketDiscountFeePrice(ticketDiscountFeeList, ticket.getCode(), ticketDiscountFee);
                    continue;
                }

                if (getInt(ticket.getTicketType()) == Constant.DISCOUNT_TICKET_TYPE_CASH && getDouble(ticket.getDiscountCash()) > 0) {
                    logger.info("will cut cash {}", ticket.getDiscountCash());
                    Double discountCash = ticket.getDiscountCash();
                    discountCash = showInteger(discountCash).doubleValue();
                    discountFee = discountFee + discountCash;
                    cutCost = cutCost + discountCash;
                    price = price - discountCash;

                    addTicketDiscountFeePrice(ticketDiscountFeeList, ticket.getCode(), discountCash);
                    continue;
                }
            }

            order.setTicketDiscountFeeList(ticketDiscountFeeList);
            order.setDiscountFee(discountFee);
        }

        return cutCost;
    }

    public void addOrderItemDiscount(List<OrderItemDiscount> orderItemDiscountList, OrderItem orderItem) {
        if (orderItem == null) {
            logger.info("order item is null");
            return;
        }

        Long orderItemId = orderItem.getId();

        Optional<OrderItemDiscount> orderItemDiscountOptional = orderItemDiscountList.stream().filter(p -> equals(p.getOrderItemId(), orderItemId)).findAny();
        if (orderItemDiscountOptional.isPresent()) {
            OrderItemDiscount orderItemDiscount = orderItemDiscountOptional.get();
            int discountNumber = orderItemDiscount.getDiscountNumber();
            if (discountNumber < orderItemDiscount.getMaxDiscountNumber()) {
                orderItemDiscount.setDiscountNumber(discountNumber + 1);
            }
        } else {
            OrderItemDiscount orderItemDiscount = new OrderItemDiscount();
            orderItemDiscount.setOrderItemId(orderItemId);
            orderItemDiscount.setMaxDiscountNumber(orderItem.getCount());
            orderItemDiscountList.add(orderItemDiscount);
        }
    }

    /**
     * 添加菜品的价格
     *
     * @param orderItem
     * @param addDiscountNumber
     */
    public void addOrderItemDiscount(OrderItem orderItem, int addDiscountNumber) {
        int discountNumber = orderItem.getDiscountNumber();
        orderItem.setDiscountNumber(discountNumber + addDiscountNumber);
    }

    /**
     * 獲取優惠券的折扣
     *
     * @return
     */
    public Double getDiscount(DiscountTicket discountTicket) {
        return 1 - discountTicket.getDiscount() / 10d;
    }

    /**
     * 获取场景ID
     *
     * @param order
     * @return
     * @throws ResponseStatusException
     */
    public Long getOrderSceneId(Order order) throws ResponseStatusException {
        if (order.getSceneId() != null) {
            return order.getSceneId();
        }

        Order orderInDb = findOrderDirect(order.getShopId(), order.getId());
        Long sceneId = orderInDb.getSceneId();
        return sceneId;
    }

    /**
     * 设置订单的分钱结账配置
     *
     * @param order
     * @param partCash
     */
    public void setPartCash(Order order, PartCash partCash) throws Exception {
        //自定义
        if (getBoolean(partCash.getCustomizedPay())) {
            order.setPartCash(partCash);
            commonService.save(order);
        } else {
            //按照人数来均分,按照原来的金额来计算
            partCash.setPerCost(formatMoneyDouble(order.getUserCost() / partCash.getPersons()));
            partCash.setPayedNumber(0);
            order.setPartCash(partCash);
            commonService.save(order);
        }
    }

    /**
     * 取消订单分钱结账或者分菜结账
     *
     * @param order
     */
    public void cancelPartOrder(Order order) throws Exception {
        order.setPartCash(null);
        order.setPartFood(null);
        commonService.save(order);
    }

    /**
     * 是否是外卖类的订单
     *
     * @param order
     * @return
     */
    public boolean isTakeoutOrder(Order order) {
        logger.info("order type is {}", order.getOrderType());

        if (getInt(order.getOrderType()) == Constant.ORDER_TYPE_TAKE_OUT) {
            logger.info("take out order");
            return true;
        }

        if (getInt(order.getOrderType()) == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
            logger.info("take out plat from order");
            return true;
        }

        if (order.getOrderType() == null) {
            logger.info("order type is null");
            return true;
        }

        logger.info("not the take out order");
        return false;
    }

    /**
     * 是否是外卖平台的订单
     *
     * @param order
     * @return
     */
    public boolean isTakeOutPlatOrder(Order order) {
        if (order == null) {
            return false;
        }

        return getInt(order.getOrderType()) == ORDER_TYPE_TAKE_OUT_PLAT;
    }

    /**
     * 取消订单
     *
     * @param shopId
     * @param orderId
     */
    public void cancelOrder(Long shopId, Long orderId) throws Exception {
        User user = ServletUtil.getUser();
        if (user == null) {
            logger.info("customer cancel order");
            customerCancelPayType(shopId, orderId);
        } else {
            if (!getBoolean(user.getAdmin())) {
                new Validator().validUser(user.id, shopId);
            }

            logger.info("b end cancel order");
            managerCancelOrder(shopId, orderId);
        }
    }

    /**
     * 餐厅管理员取消订单
     *
     * @param shopId
     * @param orderId
     */
    public void managerCancelOrder(Long shopId, Long orderId) throws Exception {
        Order orderInDb = findOrder(shopId, orderId);
        orderInDb.setStatus(ORDER_STATUS_STARTING);
        orderInDb.setUserSelectPayType(null);
        orderInDb.setLastOperateSession(null);
        orderInDb.setPartCash(null);
        orderInDb.setLockByWaiter(null);
        orderInDb.setPayTypeLock(null);
        orderInDb.setDiscountFee(null);
        orderInDb.setRealDiscountFee(null);
        orderInDb.setPayed(false);

        //曾经支付过，那么设置成已退款
        if (isNotEmpty(orderInDb.getCashPayList())) {
            orderInDb.setReturnCash(true);
        }

        orderInDb.setCashPayList(new ArrayList<>());
        //清空优惠卷的金额
        orderInDb.setTicketFee(null);

        //清空支付方式
        cleanPayType(orderInDb);

        //需要返现费用,那么需要修改待支付的金额
        orderInDb.setLeftCash(orderInDb.getUserCost());
        orderInDb.setLeft_cash_b(orderInDb.getUserCost_b());
        orderInDb.setLeft_cash_c(orderInDb.getUserCost_c());

        //如果是正在支付的订单，均需要取消掉
        List<Order> orderList = findOrderByParentId(orderId, shopId);
        logger.info("the order size is {}, order id {}, shop id {}", orderList.size(), orderId, shopId);

        for (Order o : orderList) {
            //如果是失效订单,跳过
            if (getBoolean(o.getExpiredOrder())) {
                logger.info("will skip expired order {}", o.getId());
                continue;
            }

            //如果是子订单，删除
            if (getBoolean(o.getSubOrder())) {
                logger.info("will delete sub order {}", o.getId());
                o.setFlagDelete(true);
                commonService.save(o);
                continue;
            }

            logger.info("will return order cash {}", o.getId());

            if (getBoolean(o.getPayed())) {
                logger.info("order {} return cash", o.getId());
                o.setReturnCash(true);
            }

            if (o.getStatus() != ORDER_STATUS_END) {
                o.setStatus(ORDER_STATUS_CANCEL);
                commonService.save(o);
            }

            //将支付订单设置成取消
            o.setCancel(true);
            //每个订单支付退款给用户
            if (getBoolean(o.getPayed())) {
                logger.info("pay order {}", o.getId());
                returnCashToUser(o);
            }

            commonService.save(o);
        }

        //已付款人数清零
        PartCash partCash = orderInDb.getPartCash();
        if (partCash != null) {
            partCash.setPayedNumber(0);
        }

        //分菜付款的菜清零
        getList(orderInDb.getOrderItemDetailList()).forEach(p -> {
            logger.info("will clean {} pay number to", p.getId());
            p.setPayNumber(0);
        });

        logger.info("after set order item pay number  is {}", orderInDb);

        //如果有退款，需要退回优惠卷
        orderInDb.setParentTicketCodeList(new ArrayList<>());
        orderInDb.setTicketCodeList(new ArrayList<>());

        //如果有退款，需要找出已经付款的订单，然后退回
        orderList.forEach(o -> {
            if (o.getStatus() == ORDER_STATUS_END) {
                o.setStatus(ORDER_STATUS_CANCEL);
                try {
                    commonService.save(o);
                } catch (Exception e) {
                    logger.error("e", e);
                }
            }
        });

        //这里必须保存一下，不然在数据库里面会重新读取，然后恢复已支付的菜品数量
        orderInDb.setLockOrderCashOrOrderItemList(new ArrayList<>());
        commonService.save(orderInDb);

        //如果有餐桌，那么餐桌需要判断回退到就餐中或者是部分发送
        //如果是桌上的订单，更新状态
        if (isFoodTableOrder(orderInDb)) {
            foodTableService.dealOrderFoodTableStatus(orderInDb);
        }

        //返回优惠卷,将优惠卷设置成可用
        List<String> ticketList = DiscountTicketService.getInstance().getAllTicket(orderInDb);
        if (isNotEmpty(ticketList)) {
            Long companyId = findCompanyId(orderInDb);

            for (String code : ticketList) {
                DiscountTicket ticket = DiscountTicketService.getInstance().findTicketByCode(code, companyId);
                if (ticket != null) {
                    if (!DiscountTicketService.getInstance().isWaiterLeaderTicket(ticket)) {
                        ticket.setBindingSessionId(null);
                        ticket.setUsed(false);
                        commonService.save(ticket);
                    }
                }
            }
        }

        showPrice(orderInDb, null);
        logger.info("order is {}", orderInDb);
        orderInDb.setUnassignCash(orderInDb.getUserCost());

        //剩余金额
        orderInDb.setLeftCash(orderInDb.getUserCost());
        orderInDb.setLeft_cash_b(orderInDb.getUserCost_b());
        orderInDb.setLeft_cash_c(orderInDb.getUserCost_c());
        //取消小费
        orderInDb.setTipsFee(0d);
        //取消EFT支付标记
        orderInDb.setEftPay(false);
        commonService.save(orderInDb);
        //撤销订单写入日志
        OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
        OrderOpLog orderOpLog = orderOpLogService.content(orderInDb, CANCEL_PAY_TYPE);
        orderOpLogService.cancelPayTypeLog(orderInDb, orderOpLog);

    }

    /**
     * 客人取消支付方式
     *
     * @param shopId
     */
    public void customerCancelPayType(Long shopId, Long orderId) throws Exception {
        Order orderInDb = findOrder(shopId, orderId);
        //订单不能是有部分支付了
        List<Integer> payedList = Arrays.asList(ORDER_STATUS_END, ORDER_STATUS_PART_FOOD_PAYED, ORDER_STATUS_PART_CASH_PAYED);

        //如果服务员正在操作，那么给提示
        VerifyUtil.verify(() -> !getBoolean(orderInDb.getLockByWaiter()), WAITER_OPERATE_THE_ORDER);
        logger.info("no b end action");

        //已经部分付款了，需要给提示
        //查询子订单，如果子订单已经付款了，报错了，让餐厅经理去设置
        Optional<Integer> payedOption = payedList.stream().filter(p -> p.intValue() == orderInDb.getStatus().intValue()).findFirst();
        if (payedOption.isPresent()) {
            VerifyUtil.throwError(ResponseStatus.ORDER_PART_PAID);
            return;
        }

        String sessionId = ServletUtil.getSessionId();

        //查看用户是否有在支付界面，并且选择了不是现金的支付方式，包括微信、支付宝、apple,google pay等
        PartPayService.getInstance().filterExpireOrder(orderInDb);

        List<LockOrderCashOrOrderItem> lockOrderCashOrOrderItemList = getList(orderInDb.getLockOrderCashOrOrderItemList());
        if (isNotEmpty(lockOrderCashOrOrderItemList)) {
            logger.info("will deal lock part food check");

            Optional<LockOrderCashOrOrderItem> lockOrderCashOrOrderItemOptional = lockOrderCashOrOrderItemList.stream().filter(p -> getBoolean(p.getPayed())).findAny();
            if (lockOrderCashOrOrderItemOptional.isPresent()) {
                logger.info("has payed order");
                VerifyUtil.throwError(ResponseStatus.OTHER_USER_OPERATE_THE_ORDER);
            }

            lockOrderCashOrOrderItemOptional = lockOrderCashOrOrderItemList.stream().filter(p -> {
                boolean selfSession = equals(p.getLockSessionId(), sessionId);
                boolean cashPay = p.getPayType() == 0 || p.getPayType() == ORDER_PAY_TYPE_CASH;

                //存在不是自己的会话锁定，并且支付方式不是现金
                return !selfSession && !cashPay;
            }).findAny();
            if (lockOrderCashOrOrderItemOptional.isPresent()) {
                logger.info("other user lock some food");
                VerifyUtil.throwError(ResponseStatus.OTHER_USER_OPERATE_THE_ORDER);
            }
        }

        //将现有的子订单删除掉
        List<Order> orderList = findOrderByParentId(orderId, shopId);
        for (Order subOrder : orderList) {
            subOrder.setFlagDelete(true);
            commonService.save(subOrder);
        }

        orderInDb.setStatus(ORDER_STATUS_STARTING);
        orderInDb.setLastOperateSession(null);
        orderInDb.setDiscountFee(null);
        orderInDb.setRealDiscountFee(null);

        orderInDb.setUserSelectPayType(null);
        orderInDb.setLockOrderCashOrOrderItemList(new ArrayList<>());
        orderInDb.setPayTypeLock(new PayTypeLock());
        commonService.save(orderInDb);
    }

    /**
     * 获取订单里面的菜品的最大值,再加上1，成为最新的对象
     *
     * @param shopId
     * @return
     */
    public Long generateOrderItemId(Long shopId) throws Exception {
        return OrderNoService.getInstance().getOrderItemNo();
    }

    /**
     * 发送到厨房
     *
     * @param order
     * @param sendPrinter
     */
    public void sendPrinter(Order order, SendPrinter sendPrinter) {
        Optional<SendPrinter> sendPrinterOptional = getList(order.getSendPrinterList()).stream().filter(p -> {
            return p.getOrderItemId().longValue() == sendPrinter.getOrderItemId();
        }).findAny();

        Long count = getLong(sendPrinter.getCount());

        if (count.longValue() == 0L) {
            count = 1L;
        }

        if (sendPrinterOptional.isPresent()) {
            SendPrinter findSendPrinter = sendPrinterOptional.get();
            findSendPrinter.setCount(getLong(findSendPrinter.getCount()) + count);
        } else {
            sendPrinter.setCount(count);

            if (isEmpty(order.getSendPrinterList())) {
                order.setSendPrinterList(new ArrayList<>());
            }

            order.getSendPrinterList().add(sendPrinter);
        }
    }

    public void orderDefaultValue(Order order, Shop shop) {
        order.setCompanyName(shop.getCompanyName());
        order.setCompanyId(shop.getCompanyId());
        String shopName = shopService.getShopName(shop);
        order.setShopName(shopName);
        order.setExpiredOrder(false);
        order.setTimeExpiredOrder(false);
        order.setCombineOrder(false);
        order.setParentOrder(true);
        order.setReturnCash(false);
    }

    /**
     * 是否是餐桌订单
     * <p>
     * 餐桌订单在支付完成之后，需要修改餐桌的状态
     *
     * @param order
     * @return
     */
    public boolean isFoodTableOrder(Order order) throws ResponseStatusException {
        VerifyUtil.verify(() -> order != null);

        if (order.getTableRow() != null && order.getTableColumn() != null) {
            return true;
        }

        //没有餐桌的配置
        if (isEmpty(order.getFoodTableKey())) {
            return false;
        }

        return true;
    }

    /**
     * @param order
     * @return
     */
    public boolean isDefaultFoodTableOrder(Order order) throws ResponseStatusException {
        //不是餐桌订单
        if (!isFoodTableOrder(order)) {
            return false;
        }

        int count = 0;
        for (char c : order.getFoodTableKey().toCharArray()) {

            if (equals(String.valueOf(c), SEPERATOR_KEY)) {
                count = count + 1;
            }
        }

        if (count == 1) {
            return true;
        }

        return false;
    }

    /**
     * 创建商铺的订单号
     *
     * @param shopId
     * @return
     */
    public Integer createOrderNo(Long shopId) throws Exception {
        return OrderNoService.getInstance().getOrderNo(shopId);
    }

    /**
     * 清空购物车
     *
     * @param shopId
     * @param orderId
     */
    public ResponseData cleanOrder(Long shopId, Long orderId) throws Exception {
        String lockKey = getLockKey(shopId, orderId);

        Object lock = localLockService.getLock(lockKey);
        synchronized (lock) {
            Order order = findOrder(shopId, orderId);
            List<OrderItem> orderItemDetailList = getList(order.getOrderItemDetailList());
            //只留下C端落单的菜以及B端加的菜
            orderItemDetailList = orderItemDetailList.stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
            order.setOrderItemDetailList(orderItemDetailList);

            //清空购物车
            OrderOpLogService opLogService = OrderOpLogService.getInstance();
            OrderOpLog orderOpLog = opLogService.content(order, CLEAN_ORDER_ITEM);
            opLogService.cleanOrderItem(order, orderOpLog);

            commonService.save(order);
            return commonService.createResponse(order);
        }
    }

    /**
     * 计算价格是否正确，也就是判断优惠卷是否正确
     *
     * @param priceResult
     * @return
     */
    public boolean orderPriceOk(PriceResult priceResult) {
        if (priceResult == null) {
            logger.error("price result is null");
            return false;
        }

        List<TicketResult> resultList = priceResult.getResultList();
        //没有优惠卷
        if (isEmpty(resultList)) {
            return true;
        }

        //有优惠卷，需要状态全部都是0
        return resultList.stream().allMatch(p -> {
            return getInt(p.getStatus()) == 0;
        });
    }

    /**
     * C端请求的时候，判断是否有一样的订单项
     *
     * @param reqOrderItem
     * @param customerRequest
     * @param orderInDb
     * @return
     */
    public OrderItem findSameOrderItem(OrderItem reqOrderItem, Order orderInDb, Boolean customerRequest) {
        if (!getBoolean(customerRequest)) {
            logger.info("not the customer request");
            return null;
        }

        //数据库里面还是空的，也就是第一次添加到购物车，直接添加
        List<OrderItem> orderItemDetailList = getList(orderInDb.getOrderItemDetailList());
        if (isEmpty(orderItemDetailList)) {
            logger.info("order item detail list is empty");
            return null;
        }

        List<Long> sendKithenOrderItemIdList = getList(orderInDb.getSendPrinterList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
        //这里肯定是C端的请求
        //查询相同项
        Optional<OrderItem> orderItemOptional = orderItemDetailList.stream().filter(orderItem -> {
            //找到了，还要是未发送到厨房的,也没有落单的菜
            return !getBoolean(orderItem.getCheckout()) && !sendKithenOrderItemIdList.contains(orderItem.getId()) && equals(reqOrderItem, orderItem);
        }).findFirst();

        //找到了
        if (orderItemOptional.isPresent()) {
            return orderItemOptional.get();
        }

        return null;
    }

    /**
     * 查询在营业时间内的订单
     *
     * @param shop
     * @return
     */
    public List<Order> queryOpenTimeOrderList(Shop shop) {
        if (shop == null) {
            logger.info("shop is null");
            return new ArrayList<>();
        }

        Order order = new Order();
        order.setShopId(shop.getId());
        order.setEntity(true);
        order.setBusinessEndShow(true);

        if (shop.getOpenTime() == null) {
            order.setStartCreateTime(0L);
        } else {
            order.setStartCreateTime(shop.getOpenTime());
        }

        order.setEndCreateTime(System.currentTimeMillis());
        logger.info("close report start create time {} - {}, end create time {} - {}, shopId {}", order.getStartCreateTime(), DateUtil.formatDate(order.getStartCreateTime()), order.getEndCreateTime(), DateUtil.formatDate(order.getEndCreateTime()), order.getShopId());

        List<Order> orderList = commonService.searchAll(order);
        return orderList;
    }


    /**
     * 查询店铺当天的订单
     *
     * @param shopId
     * @return
     */
    public List<Order> queryOrderFromOpenTime(Long shopId) throws Exception {
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Long startTime = shop.getOpenTime();
        long endTime = System.currentTimeMillis();
        Order order = new Order();
        order.setShopId(shopId);
        order.setStartCreateTime(startTime);
        order.setEndCreateTime(endTime);
        order.setStatus(ORDER_STATUS_END);
        List<Order> orderList = commonService.searchAll(order);

        logger.info("before filter order size is {}", orderList.size());
        orderList = orderList.stream().filter(o -> {
            return o.getPayType() != null;
        }).collect(Collectors.toList());
        logger.info("after filter order size is {}", orderList.size());

        return orderList;
    }

    /**
     * 如果是C端的请求，需要判断是否已经发送到厨房了
     *
     * @param deleteOrderItemList
     * @param customerRequest
     */
    public void checkDeleteItem(List<OrderItem> deleteOrderItemList, List<SendPrinter> sendPrinterList, Boolean customerRequest) throws ResponseStatusException {
        //B端的请求通过
        if (!getBoolean(customerRequest)) {
            logger.info("its b front request , ok ");
            return;
        }

        //没有发送到厨房，可以直接删除
        if (isEmpty(sendPrinterList)) {
            return;
        }

        List<Long> printOrderItemIdList = sendPrinterList.stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
        Optional<OrderItem> matchTheItem = deleteOrderItemList.stream().filter(orderItem -> printOrderItemIdList.contains(orderItem.getId())).findAny();

        //如果匹配上了，说明在删除已经发送到厨房的
        VerifyUtil.verify(() -> !matchTheItem.isPresent(), ResponseStatus.ITEM_SEND_TO_KITCHEN);
    }

    /**
     * 是否是部分付款
     *
     * @param order
     * @return
     */
    public boolean isOrderPartPay(Order order) throws ResponseStatusException {
        VerifyUtil.verify(() -> order != null);
        Integer status = getInt(order.getStatus());
        List<Integer> partPayed = Arrays.asList(ORDER_STATUS_PART_CASH_PAYED, ORDER_STATUS_PART_FOOD_PAYED, ORDER_STATUS_PART_CASH_CUSTOMIZED_PAYED);
        return partPayed.contains(status);
    }

    /**
     * 订单至少有一过一种支付
     *
     * @param order
     * @return
     */
    public boolean isOrderAtLeastPayed(Order order) {
        Integer status = getInt(order.getStatus());
        List<Integer> statusList = Arrays.asList(ORDER_STATUS_PART_CASH_PAYED, ORDER_STATUS_PART_FOOD_PAYED, ORDER_STATUS_PART_CASH_CUSTOMIZED_PAYED, ORDER_STATUS_END);
        return statusList.contains(status);
    }

    /**
     * 是否是正在支付的订单
     *
     * @param order
     */
    public boolean isOrderPaying(Order order) throws ResponseStatusException {
        VerifyUtil.verify(() -> order != null);

        int status = getInt(order.getStatus());
        boolean paying = status > ORDER_STATUS_STARTING && status != ORDER_STATUS_CANCEL;
        return paying;
    }

    /**
     * 如果是正在结算的订单，不能再添加，修改，删除
     *
     * @param order
     * @throws ResponseStatusException
     */
    public void checkPayingOrder(Order order) throws ResponseStatusException {
        boolean orderPaying = isOrderPaying(order);
        if (ServletUtil.isCustomerRequest()) {
            VerifyUtil.verify(() -> !orderPaying, ResponseStatus.C_END_LOCK_ORDER);
        } else {
            VerifyUtil.verify(() -> !orderPaying, ResponseStatus.ORDER_LOCKED);
        }
    }

    /**
     * 添加订单的运营模式设置
     *
     * @param order
     */
    public void addRunModelConfigForOrder(Order order) throws Exception {
        //外卖平台的单不检验
        if (getBoolean(order.getOrderType() == ORDER_TYPE_TAKE_OUT_PLAT)) {
            logger.info("{} its order take out plat order");
            return;
        }

        Scene matchScene = null;

        if (order.getSceneId() == null) {
            logger.info("will find the match scene");
            SceneService.getInstance().findTheMatchScene(order.getShopId());
        } else {
            logger.info("will find the the scene id {}", order.getSceneId());
            matchScene = SceneService.getInstance().findScene(order.getSceneId());
        }

        if (matchScene == null) {
            logger.info("can not find the match scene");
            return;
        }

        logger.info("find the match scene for order");

        List<RunModuleScene> runModelSceneList = null;

        //总二维码场景
        if (!isFoodTableOrder(order)) {
            runModelSceneList = matchScene.getRunModuleSceneList().stream().filter(p -> getInt(p.getType()) == RUN_MODEL_TYPE_TOTAL).collect(Collectors.toList());
        } else if (getInt(order.getUniqueCode()) == 0) {
            //固定餐桌
            runModelSceneList = matchScene.getRunModuleSceneList().stream().filter(p -> getInt(p.getType()) == RUN_MODEL_TYPE_FOOD_TABLE_FIX).collect(Collectors.toList());
        } else if (getInt(order.getUniqueCode()) != 0) {
            runModelSceneList = matchScene.getRunModuleSceneList().stream().filter(p -> getInt(p.getType()) == RUN_MODEL_TYPE_FOOD_TABLE_WAITER_QR).collect(Collectors.toList());
        }

        if (isNotEmpty(runModelSceneList)) {
            RunModuleScene runModuleScene = runModelSceneList.get(0);
            order.setPayFirst(runModuleScene.getPayFirst());
            order.setOnlinePay(runModuleScene.getOnlinePay());
            logger.info("set the runMode with scene {}, run module type is {}", matchScene.getId(), runModuleScene);
            return;
        }

        logger.info("can not find the runmode with scene {}", matchScene.getId());
        return;
    }

    private void dealOrderRunModule(Order order, List<RunModel> runModelList, int modelType, Function<RunModel, Boolean> filterCondition) {
        Optional<RunModel> runModelOption = runModelList.stream().filter(p -> p.getModelType() == modelType).findFirst();
        if (runModelOption.isPresent()) {
            RunModel runMode = runModelOption.get();
            if (filterCondition.apply(runMode)) {
                Optional<RunModuleScene> runModuleSceneOptional = filterRunModuleScene(runMode.getRunModuleSceneList());

                if (runModuleSceneOptional.isPresent()) {
                    RunModuleScene runModuleScene = runModuleSceneOptional.get();
                    order.setPayFirst(runModuleScene.getPayFirst());
                    order.setOnlinePay(runModuleScene.getOnlinePay());
                }

                //没有找到匹配项
                logger.info("can not match the scene time");
            }
        }
    }

    /**
     * 过滤出符合当前时间的模式配置
     *
     * @param runModuleSceneList
     * @return
     */
    public Optional<RunModuleScene> filterRunModuleScene(List<RunModuleScene> runModuleSceneList) {
        if (isEmpty(runModuleSceneList)) {
            logger.info("run module scene list is empty");
            return Optional.empty();
        }

        for (RunModuleScene runModuleScene : runModuleSceneList) {
            try {
                if (!getBoolean(runModuleScene.getEnable())) {
                    logger.info("not enable");
                    continue;
                }

                Scene scene = SceneService.getInstance().findScene(runModuleScene.getId());
                if (isEmpty(scene.getTimeConfigList())) {
                    logger.info("scene time config is empty, scene id is {}", scene.getId());
                    continue;
                }

                Optional<SceneTimeConfig> sceneTimeConfigOptional = scene.getTimeConfigList().stream().filter(p -> SceneService.getInstance().isMatchTimeConfig(p)).findFirst();
                //找到了
                if (sceneTimeConfigOptional.isPresent()) {
                    return Optional.of(runModuleScene);
                }

            } catch (Exception e) {
                logger.error("find scene error", e);
                continue;
            }
        }

        //没有找到
        logger.info("can not find the scene");
        return Optional.empty();
    }

    /**
     * 查询订单列表
     *
     * @param orderIdList
     * @param shopId
     * @return
     */
    public List<Order> findOrderList(List<Long> orderIdList, Long shopId) {
        return orderIdList.stream().map(orderId -> {
            try {
                return findOrder(shopId, orderId);
            } catch (Exception e) {
                logger.error("e", e);
                return null;
            }
        }).filter(p -> p != null).collect(Collectors.toList());
    }

    /**
     * 判断订单是否有已经支付完成的订单
     *
     * @param orderId
     * @param shopId
     * @return
     */
    public boolean hasPayedOrder(Long shopId, Long orderId) {
        List<Order> filterOrderList = findPayedOrder(shopId, orderId);
        return filterOrderList.size() != 0;
    }

    /**
     * 通过父订单ID去查询所有已经支付的订单，并且没有取消的订单
     *
     * @param shopId
     * @param orderId
     * @return
     */
    public List<Order> findPayedOrder(Long shopId, Long orderId) {
        List<Order> orderList = findOrderByParentId(orderId, shopId);

        //已经支付完的订单，并且没有取消的订单
        List<Order> filterOrderList = orderList.stream().filter(p -> getBoolean(p.getPayed() && !getBoolean(p.getCancel()) && !getBoolean(p.getSubOrder()))).collect(Collectors.toList());
        return filterOrderList;
    }

    /**
     * 查询所有的支付订单
     *
     * @param shop
     * @return
     */
    public List<Order> findPayedOrder(Shop shop) {
        Order order = new Order();
        order.setShopId(shop.getId());
        order.setStartCreateTime(shop.getOpenTime());
        return commonService.searchAll(order).stream().filter(o -> !getBoolean(o.getParentOrder())).filter(o -> !getBoolean(o.getSubOrder())).filter(o -> getBoolean(o.getPayed())).filter(o -> getBoolean(o.getReturnCash())).collect(Collectors.toList());
    }

    public Optional<Order> filterFoodTableOrder(List<Order> orderList) {
        return orderList.stream().filter(order -> {
            try {
                return isFoodTableOrder(order);
            } catch (ResponseStatusException e) {
                return false;
            }
        }).findFirst();
    }

    /**
     * 合并订单
     *
     * @param orderList
     * @return
     */
    public Order combineOrderList(List<Order> orderList) throws Exception {
        Order newOrder = new Order();
        newOrder.setOrderItemDetailList(new ArrayList<>());
        Optional<Order> foodTableOrderOptional = filterFoodTableOrder(orderList);

        Order oneCombineOrder = null;
        if (foodTableOrderOptional.isPresent()) {
            oneCombineOrder = foodTableOrderOptional.get();
        } else {
            oneCombineOrder = orderList.get(0);
        }

        //生成订单编号
        Integer orderNo = createOrderNo(oneCombineOrder.getShopId());
        BeanUtils.copyProperties(oneCombineOrder, newOrder, "id", "orderItemDetailList", "orderItemDetailJson", "payType", "parentOrderId", "parentTicketCodeList", "parentTicketJson", "ticketCodeList", "ticketJson", "userSelectPayType", "partCash", "partCashJson", "partFood", "returnCash", "sendPrinterJson", "sendPrinterList", "satisfy", "satisfyAndCutCode");

        //重新设置不同的属性
        newOrder.setCreateTime(System.currentTimeMillis());
        newOrder.setCreateDate(DateUtil.formatDate(newOrder.getCreateTime()));
        newOrder.setCombineOrder(false);
        newOrder.setOrderNo(orderNo);

        //修改用户的付的钱
        newOrder.setUserCost_b(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getUserCost_b())).sum());
        newOrder.setUserCost_c(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getUserCost_c())).sum());
        newOrder.setUserCost(showDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getUserCost())).sum()));

        //returncash为false，服务员端闭店报告查询未支付时用到
        newOrder.setReturnCash(false);

        //修改剩余金额
        newOrder.setLeftCash(showDouble(newOrder.getUserCost()));
        newOrder.setLeft_cash_b(showDouble(newOrder.getUserCost_b()));
        newOrder.setLeft_cash_c(showDouble(newOrder.getUserCost_c()));

        //修改小计
        newOrder.setCostOrigin(showDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getCostOrigin())).sum()));
        newOrder.setCostOrigin_b(showDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getCostOrigin_b())).sum()));
        newOrder.setCostOrigin_c(showDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getCostOrigin_c())).sum()));

        //修改服务费
        newOrder.setServiceFee(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getServiceFee())).sum()));
        newOrder.setServiceFee_b(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getServiceFee_b())).sum()));
        newOrder.setServiceFee_c(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getServiceFee_c())).sum()));

        //如果是美国版本，添加消费税
        if (Config.getInstance().isUsVersion()) {
            newOrder.setConsumptionTax(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getConsumptionTax())).sum()));
            newOrder.setConsumptionTax_b(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getConsumptionTax_b())).sum()));
            newOrder.setConsumptionTax_c(showMoneyDouble(orderList.stream().mapToDouble(p -> showMoneyDouble(p.getConsumptionTax_c())).sum()));
        }

        //添加菜品列表
        newOrder.getOrderItemDetailList().addAll(orderList.stream().flatMap(p -> getList(p.getOrderItemDetailList()).stream()).collect(Collectors.toList()));
        newOrder.setPersons(orderList.stream().mapToInt(p -> getInt(p.getPersons())).sum());
        newOrder.setStatus(Constant.ORDER_STATUS_STARTING);
        newOrder.setPayed(false);
        newOrder.setCancel(false);

        if (isEmpty(newOrder.getSendPrinterList())) {
            newOrder.setSendPrinterList(new ArrayList<>());
        }

        //发送到厨房列表也合并
        newOrder.getSendPrinterList().addAll(orderList.stream().flatMap(p -> getList(p.getSendPrinterList()).stream()).collect(Collectors.toList()));
        //包装费合并
        newOrder.setPackageFee(orderList.stream().mapToDouble(p -> getDouble(p.getPackageFee())).sum());

        //添加合并的订单列表
        List<Long> combineOrderList = orderList.stream().map(p -> p.getId()).collect(Collectors.toList());
        newOrder.setCombineOrderList(combineOrderList);

        commonService.createObject(newOrder);

        //如果是餐桌订单，那么需要修改餐桌状态
        for (Order order : orderList) {
            FoodTableService foodTableService = FoodTableService.getInstance();
            foodTableService.dealOrderFoodTableStatus(order);
        }

        return newOrder;
    }

    /**
     * 获取未打印的菜品列表
     *
     * @param order
     * @return
     */
    public List<Long> getUnPrinterOrderItemIdList(Order order) {
        //列表本身是空，那么返回空列表
        if (isEmpty(order.getOrderItemDetailList())) {
            return new ArrayList<>();
        }

        List<OrderItem> orderItems = null;
        boolean bEndPayOrder = ServletUtil.isBEndPayOrder();

        if (bEndPayOrder) {
            orderItems = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList());
        } else {
            orderItems = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
        }

        //如果没有打印过，那么整个ID列表都返回
        if (isEmpty(order.getSendPrinterList())) {
            return getList(orderItems.stream().map(p -> p.getId()).collect(Collectors.toList()));
        }

        List<Long> printerIdList = getList(order.getSendPrinterList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
        //过滤没有打印的列表
        return getList(orderItems.stream().filter(p -> !printerIdList.contains(p.getId().longValue())).map(p -> p.getId()).collect(Collectors.toList()));
    }

    /**
     * 退回过期订单的费用
     *
     * @param reqOrder
     * @throws Exception
     */
    public void returnExpireOrder(Order reqOrder) throws Exception {
        Order orderInDb = findOrder(reqOrder.getShopId(), reqOrder.getId());
        logger.info("return cash order is {}", orderInDb);
        returnCashToUser(orderInDb);
        orderInDb.setCancel(true);
        orderInDb.setReturnCash(true);
        commonService.save(orderInDb);
    }

    /**
     * 退款给用户
     *
     * @param orderInDb
     */
    public void returnCashToUser(Order orderInDb) throws Exception {
        //修改订单类型的时候，不退款
        if (isOrderPayModifyRequest()) {
            return;
        }

        //如果是微信，支付宝，并且有qf的syssn时候，才需要退款
        if (isQfPay(orderInDb)) {
            Long shopId = orderInDb.getShopId();
            Shop shop = ShopService.getInstance().findShopById(shopId);
            logger.info("shop qf code is {} key {}, qfsid {}", AES.decrypt(shop.getQfCode()), AES.decrypt(shop.getQfKey()), shop.getQfSid());
            QfPayClient qfPayClient = new QfPayClient(AES.decrypt(shop.getQfCode()), AES.decrypt(shop.getQfKey()), shop.getQfSid());
            qfPayClient.returnPayment(orderInDb);
        } else if (StripeService.getInstance().isStripeTerminal(orderInDb)) {
            //终端支付的退款，只能是取消订单
            String stripePaymentId = orderInDb.getStripePaymentId();
            StripeService.getInstance().cancelPayment(orderInDb.getShopId(), stripePaymentId);
        } else if (StripeService.getInstance().isStripePay(orderInDb)) {
            logger.info("will refunds for the stripe order {}", orderInDb.getId());
            StripeService.getInstance().refunds(orderInDb);
        } else {
            logger.info("nothing to return");
        }

        //订单退款写入日志
        OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
        OrderOpLog orderOpLog = orderOpLogService.content(orderInDb, ORDER_RETURN_CASH);
        orderOpLogService.orderReturnCashLog(orderInDb, orderOpLog);


        //针对每一个订单，如果产生了消费后金额优惠卷，那么将该优惠卷设置为已用。
        DiscountTicket ticket = new DiscountTicket();
        ticket.setCreateSubOrderId(orderInDb.getId());
        ticket.setShopId(orderInDb.getShopId());
        Optional<DiscountTicket> discountTicketOptional = commonService.searchOneOptional(ticket);

        //将小票设置成已使用，不影响显示
        if (discountTicketOptional.isPresent()) {
            DiscountTicket discountTicket = discountTicketOptional.get();
            if (!DiscountTicketService.getInstance().isWaiterLeaderTicket(discountTicket)) {
                discountTicket.setUsed(true);
                commonService.save(discountTicket);
            }
        }
    }

    /**
     * 是否是qf order
     *
     * @param orderInDb
     * @return
     */
    public boolean isQfPay(Order orderInDb) {
        if (isEmpty(orderInDb.getSyssn())) {
            logger.info("pf pay sn is empty");
            return false;
        }

        Integer payType = getInt(orderInDb.getPayType());
        if (Arrays.asList(ORDER_PAY_TYPE_WEIXIN, ORDER_PAY_TYPE_ALIPAY).contains(payType)) {
            logger.info("weixin pay or ali pay");
            return true;
        }

        logger.info("not qf pay");
        return false;
    }

    /**
     * 订单退单
     *
     * @param payedOrder
     */
    public void returnCash(Order payedOrder) throws Exception {
        boolean orderPayModifyRequest = isOrderPayModifyRequest();

        //正常退款
        if (!orderPayModifyRequest) {
            //表示取消了
            payedOrder.setCancel(true);
            //表示取消的同时，还退款了
            payedOrder.setReturnCash(true);
            payedOrder.setFlagDelete(true);
            commonService.save(payedOrder);
        } else {
            //修改支付方式
            realDeleteOrder(payedOrder);
        }

        Long parentOrderId = payedOrder.getParentOrderId();
        Order parentOrder = findOrder(payedOrder.getShopId(), parentOrderId);

        //如果有优惠券，那么修改优惠的金额
        if (payedOrder.getRealDiscountFee() != null) {
            Double discountFee = getDouble(parentOrder.getDiscountFee());
            parentOrder.setDiscountFee(showMoneyDouble(discountFee - payedOrder.getRealDiscountFee()));
        }

        //如果是现金的退款，那么需要从现金列表中删除
        List<CashPay> cashPayList = getList(parentOrder.getCashPayList());
        cashPayList = cashPayList.stream().filter(p -> !equals(p.getOrderId(), payedOrder.getId())).collect(Collectors.toList());
        parentOrder.setCashPayList(cashPayList);
        commonService.save(parentOrder);

        //回退积分
        if (payedOrder.getCustomerId() != null) {
            CustomerService customerService = CustomerService.getInstance();
            Optional<ScoreHistory> scoreHistoryOptional = customerService.findScoreHistory(payedOrder.getCustomerId(), payedOrder.getShopId(), payedOrder.getId());
            if (scoreHistoryOptional.isPresent()) {
                ScoreHistory scoreHistory = scoreHistoryOptional.get();
                logger.info("begin to find the score history, {}", scoreHistory.getValue());
                Customer customer = customerService.findCustomer(payedOrder.getCustomerId());
                customer.setScore(customer.getScore() - scoreHistory.getValue());
                customer.setScoreHistory(customer.getScoreHistory() - scoreHistory.getValue());

                Long levelHistoryId = customer.getVipLevelId();

                //找会员等级
                Optional<VipLevel> vipLevelOptional = customerService.findCustomerVipLevel(customer.getScoreHistory(), payedOrder.getCompanyId());
                if (vipLevelOptional.isPresent()) {
                    customer.setVipLevelId(vipLevelOptional.get().getId());
                    logger.info("will set the user to level {}", customer.getVipLevelId());

                    //会员等级发生了变化，将已经发送出去的券发成已使用
                    if (!equals(levelHistoryId, vipLevelOptional.get().getId())) {
                        List<CustomerTicket> customerTicketList = customerService.findCustomerTicket(customer.getId(), levelHistoryId);
                        for (CustomerTicket customerTicket : customerTicketList) {
                            customerTicket.setUsed(true);
                            commonService.save(customerTicket);

                            //将真实的优惠券也设置成已使用
                            Optional<DiscountTicket> discountTicketOptional = DiscountTicketService.getInstance().findTicketOptional(customerTicket.getTicketId());
                            if (discountTicketOptional.isPresent()) {
                                DiscountTicket discountTicket = discountTicketOptional.get();
                                if (!DiscountTicketService.getInstance().isWaiterLeaderTicket(discountTicket)) {
                                    discountTicket.setUsed(true);
                                    commonService.save(discountTicket);
                                }
                            }
                        }
                    }
                }

                commonService.save(customer);

                //删除积分历史记录
                commonService.delete(scoreHistory, false);
            }

        }

        Integer userSelectPayType = getInt(payedOrder.getUserSelectPayType());

        //如果是分菜结账，那么回退已支付数量
        if (userSelectPayType == USER_SELECT_PAY_TYPE_PART_FOOD) {
            for (OrderItem orderItem : getList(parentOrder.getOrderItemDetailList())) {
                OrderItem parentOrderItem = filterOrderItemList(parentOrder, orderItem.getId());
                Integer payNumber = getInt(parentOrderItem.getPayNumber());
                payNumber = payNumber - 1;
                if (payNumber < 0) {
                    logger.info("pay number less than 0");
                    payNumber = 0;
                }

                parentOrderItem.setPayNumber(payNumber);
            }

            //再判断是否是部分支付，还是部分发送，不是就餐中
            boolean someItemPayed = getList(parentOrder.getOrderItemDetailList()).stream().anyMatch(p -> getInt(p.getPayNumber()) > 0);
            //存在一个已付款，部分付款
            if (someItemPayed) {
                parentOrder.setStatus(ORDER_STATUS_PART_FOOD_PAYED);
            } else {
                //回退到分菜结账初始状态
                parentOrder.setStatus(ORDER_STATUS_PART_FOOD);
            }

            //处理付款方式，查询所有已付款但是未退款的子订单，重新设置付款方式
            cleanPayType(parentOrder);
            List<Order> orderList = findOrderByParentId(parentOrderId, payedOrder.getShopId()).stream().filter(p -> getBoolean(p.getPayed()) && !getBoolean(p.getReturnCash())).collect(Collectors.toList());

            int parentOrderBit = 0;

            for (Order subOrder : orderList) {
                addPayTypeBit(parentOrderBit, subOrder.getPayType());
            }

            //父订单的未支付余额修改
            Double leftCash = parentOrder.getLeftCash();
            parentOrder.setLeftCash(showDouble(getDouble(leftCash) + getDouble(payedOrder.getPayOrderCost())));
            parentOrder.setLeft_cash_b(parentOrder.getLeftCash());

            logger.info("parent order is {}", parentOrder);
            commonService.save(parentOrder);
        } else if (userSelectPayType == USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON || userSelectPayType == USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED) {
            //父订单的未支付余额修改
            Double leftCash = parentOrder.getLeftCash();
            parentOrder.setLeftCash(showDouble(getDouble(leftCash) + getDouble(payedOrder.getPayOrderCost())));
            parentOrder.setLeft_cash_b(parentOrder.getLeftCash());

            logger.info("parent order is {}", parentOrder);
            commonService.save(parentOrder);
        }

        //处理父订单状态
        List<Order> payedOrderList = findPayedOrder(parentOrder.getShopId(), parentOrder.getId());
        if (payedOrderList.size() > 0) {
            switch (getInt(parentOrder.getUserSelectPayType())) {
                case USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON:
                    parentOrder.setStatus(ORDER_STATUS_PART_CASH_PAYED);
                    break;
                case USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED:
                    parentOrder.setStatus(ORDER_STATUS_PART_CASH_CUSTOMIZED_PAYED);
                    break;
                case USER_SELECT_PAY_TYPE_PART_FOOD:
                    parentOrder.setStatus(ORDER_STATUS_PART_FOOD_PAYED);
                    break;
                default:
                    logger.info("not the part pay");
            }

            commonService.save(parentOrder);
        } else {
            switch (getInt(parentOrder.getUserSelectPayType())) {
                case USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON:
                    parentOrder.setStatus(ORDER_STATUS_PART_CASH);
                    break;
                case USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED:
                    parentOrder.setStatus(ORDER_STATUS_PART_CASH_CUSTOMIZED);
                    break;
                case USER_SELECT_PAY_TYPE_PART_FOOD:
                    parentOrder.setStatus(ORDER_STATUS_PART_FOOD);
                    break;
                default:
                    logger.info("not the part pay");
            }
        }

        //如果是餐桌订单，需要计算一下餐桌状态
        //一个订单对应多个餐桌，所以查询出来的餐桌上面对应的订单场景一定要跟当前的订单的场景相同
        if (isFoodTableOrder(parentOrder)) {
            logger.info("return cash:parent order {} deal food table status", parentOrder.getId());
            foodTableService.dealOrderFoodTableStatus(parentOrder);
        }

        //将已使用的优惠券改成可以使用的状态
        if (isNotEmpty(payedOrder.getTicketCodeList())) {
            if (payedOrder.getCustomerId() == null) {
                for (String code : getList(payedOrder.getTicketCodeList())) {
                    setOrderTicketToUnused(payedOrder, code);
                }
            } else {
                //如果是会员，那么判断该CODE是否不限量的优惠券，不限量的不处理状态，限量的优惠券处理状态
                List<String> codeList = getList(payedOrder.getTicketCodeList());
                CustomerService customerService = CustomerService.getInstance();
                Long customerId = payedOrder.getCustomerId();

                for (String code : codeList) {
                    Optional<CustomerTicket> customerTicketOptional = customerService.findCustomerTicket(customerId, code);
                    if (customerTicketOptional.isPresent()) {
                        CustomerTicket customerTicket = customerTicketOptional.get();

                        //限量使用的修改状态
                        if (getBoolean(customerTicket.getLimitNumber())) {
                            setOrderTicketToUnused(payedOrder, code);
                            customerTicket.setUsed(false);
                        }
                    }
                }
            }
        }

        //如果还有消费后返回的优惠券，那么回退
        if (payedOrder.getCustomerId() != null) {
            CustomerTicket customerTicket = new CustomerTicket();
            customerTicket.setOrderId(payedOrder.getId());
            Optional<CustomerTicket> customerTicketOptional = commonService.searchOneOptional(customerTicket);
            if (customerTicketOptional.isPresent()) {
                CustomerTicket customerTicketAfterCash = customerTicketOptional.get();
                customerTicketAfterCash.setUsed(true);
                commonService.save(customerTicketAfterCash);
            }
        }

        returnCashToUser(payedOrder);
    }

    private void setOrderTicketToUnused(Order payedOrder, String code) throws Exception {
        Long shopId = payedOrder.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Long companyId = shop.getCompanyId();
        DiscountTicket discountTicket = DiscountTicketService.getInstance().findTicketByCode(code, companyId);
        if (!DiscountTicketService.getInstance().isWaiterLeaderTicket(discountTicket)) {
            discountTicket.setUsed(false);
            commonService.save(discountTicket);
        }
    }

    /**
     * 购物车里面的菜品的国际化处理
     *
     * @param orderItem
     * @param itemInDb
     */
    public void orderItemZhEn(OrderItem orderItem, Item itemInDb) throws Exception {
        orderItem.setItemName(itemInDb.getName());
        orderItem.setItemName_zh(itemInDb.getName_zh());
        orderItem.setItemName_en(itemInDb.getName_en());

        //如果有规格项，那么依次处理规格项;
        List<ItemDetail> itemDetailList = orderItem.getItemDetailList();
        if (isNotEmpty(itemDetailList)) {
            logger.info("will deal zh en in order");
            //修改中英文
            for (ItemDetail itemDetail : itemDetailList) {
                logger.info("will deal zh en in item detail");
                ItemDetail filterItemDetail = itemService.filterItemDetail(itemDetail.getId(), itemInDb);
                itemDetail.setName(filterItemDetail.getName());
                itemDetail.setName_zh(filterItemDetail.getName_zh());
                itemDetail.setName_en(filterItemDetail.getName_en());

                List<NameAndPrice> nameAndPriceList = itemDetail.getNameAndPriceList();
                if (isNotEmpty(nameAndPriceList)) {
                    logger.info("will deal zh en in name and price list");
                    for (NameAndPrice nameAndPrice : nameAndPriceList) {
                        NameAndPrice filterNameAndPrice = itemService.filterNameAndPrice(nameAndPrice.getId(), itemDetail);
                        nameAndPrice.setName(filterNameAndPrice.getName());
                        nameAndPrice.setName_zh(filterNameAndPrice.getName_zh());
                        nameAndPrice.setName_en(filterNameAndPrice.getName_en());
                    }
                }
            }
        }

        //套餐里面的国际化处理
        if (getBoolean(itemInDb.getSetMenu())) {
            List<SetMenuOneItem> setMenuItemList = getList(orderItem.getSetMenuOneItemList());

            for (SetMenuOneItem setMenuOneItem : setMenuItemList) {
                if (setMenuOneItem.getId() != null) {
                    logger.info("will update item {} zh and en", setMenuOneItem.getId());
                    //那么添加每一项的中英文
                    SetMenuOneItem setMenuOneItemInDb = itemService.filterSetMenuOneItem(itemInDb, setMenuOneItem.getId());
                    ZhEnService.getInstance().updateSyncZhEn(setMenuOneItem, setMenuOneItemInDb);
                }

                List<Item> itemList = getList(setMenuOneItem.getItemList());
                for (Item detailItem : itemList) {
                    if (getLong(detailItem.getId()) == 0L) {
                        continue;
                    }

                    Item detailItemInDb = itemService.findItem(detailItem.getId());
                    //如果还有规格项，那么规格项也添加国际化
                    for (ItemDetail itemDetail : getList(detailItem.getItemDetailList())) {
                        ItemDetail itemDetailInDb = itemService.filterItemDetail(itemDetail.getId(), detailItemInDb);
                        logger.info("will sync update item detail {}", itemDetailInDb.getId());
                        ZhEnService.getInstance().updateSyncZhEn(itemDetail, itemDetailInDb);

                        for (NameAndPrice nameAndPrice : getList(itemDetail.getNameAndPriceList())) {
                            NameAndPrice nameAndPriceInDb = itemService.filterNameAndPrice(nameAndPrice.getId(), detailItemInDb);
                            logger.info("will sync update nameAndPrice {}", nameAndPrice.getId());
                            ZhEnService.getInstance().updateSyncZhEn(nameAndPrice, nameAndPriceInDb);
                        }
                    }
                }
            }
        }
    }

    /**
     * 删除当天所有未支付的订单
     *
     * @param shopId
     */
    public void allOrderCloseQrScanShow(Long shopId) throws Exception {
        //将当天的所有订单都关闭二维码显示
        List<Order> orderList = queryOrderFromOpenTime(shopId);
        for (Order order : orderList) {
            order.setCloseQrScanShow(true);
            commonService.save(order);
        }
    }

    /**
     * 判断一个订单里面的菜是否已经都发送到厨房了
     *
     * @param order
     * @return
     */
    public boolean isAllSendPrint(Order order) {
        List<OrderItem> orderItemDetailList = getList(order.getOrderItemDetailList());
        orderItemDetailList = orderItemDetailList.stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
        List<Long> sendOrderItemIdList = getList(order.getSendPrinterList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());

        for (OrderItem orderItem : orderItemDetailList) {
            //查询这个菜是否已经发送到厨房了
            if (sendOrderItemIdList.contains(orderItem.getId().longValue())) {
                continue;
            }

            logger.info("not all the item send to kitchen");
            return false;
        }

        logger.info("all the item send to kitchen");
        return true;
    }

    /**
     * 订单是否部分发送
     *
     * @param order
     * @return
     */
    public boolean isPartSend(Order order) {
        List<SendPrinter> sendPrinterList = getList(order.getSendPrinterList());
        if (isEmpty(sendPrinterList)) {
            logger.info("send printer list is empty");
            return false;
        }

        //确实已经发送过厨房了，判断是否是全部发送了，还是部分发送
        if (isAllSendPrint(order)) {
            logger.info("all order item send to kitchen");
            return false;
        }

        //既然有发送到厨房的，并且没有发送完，那么就是部分发送厨房了
        logger.info("part order item send to kitchen");
        return true;
    }

    /**
     * 将查询条件转化成boolean值
     *
     * @param order
     */
    public void payTypeListToBitPayType(Order order) {
        if (order == null) {
            logger.info("order is null");
            return;
        }

        List<Integer> payTypeList = order.getPayTypeList();
        if (isEmpty(payTypeList)) {
            logger.info("pay type list is null");
            return;
        }

        int bitPayType = Long.valueOf(intListToBitNumber(payTypeList)).intValue();
        order.setPayTypeBit(bitPayType);
    }

    /**
     * 查询锁定的订单
     * <p>
     * 查询有锁定量，但是没有过期的订单
     * 在最近2小时内查询，并且锁定时间已经超过了10分钟
     *
     * @param shopId
     * @return
     */
    public List<Order> findLockOrderList(Long shopId) throws Exception {
        //return currentTimeMillis - getLong(p.getConfirmTime()) > config.confirmExpireTime();
        //查询两个小时之内，有锁定量的订单，并且订单已经超过的
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        long confirmExpireTime = config.confirmExpireTime();
        long orderExpireTime = System.currentTimeMillis() - confirmExpireTime;
        List<Order> lockCountOrderList = orderDao.findLockCountOrderList(shopId, getLong(shop.getOpenTime()), System.currentTimeMillis(), true, true, false, orderExpireTime);

        for (Order order : lockCountOrderList) {
            commonService.dealFieldMapping(order, false);
        }

        return lockCountOrderList;
    }

    /**
     * 单个订单不能超过最大值
     *
     * @param orderItem
     */
    public void checkOrderItemMaxNumber(OrderItem orderItem) throws ResponseStatusException {
        if (orderItem == null) {
            logger.info("order item is null");
            return;
        }

        VerifyUtil.verify(() -> getInt(orderItem.getCount()) <= config.oneOrderItemMaxNumber(), ResponseStatus.ONE_ORDER_ITEM_OVER_LIMIT);
    }

    /**
     * 购物车里面的每一个ID到真实的菜
     *
     * @param order
     * @param orderItemIdList
     * @return
     */
    public List<OrderItem> filterOrderItemList(Order order, List<Long> orderItemIdList) {
        return getList(order.getOrderItemDetailList()).stream().filter(p -> orderItemIdList.contains(p.getId().longValue())).collect(Collectors.toList());
    }

    /**
     * 转化成ID列表
     *
     * @param orderItemList
     * @return
     */
    public List<Long> toOrderItemIdList(List<OrderItem> orderItemList) {
        return getList(orderItemList).stream().map(p -> p.getId()).collect(Collectors.toList());
    }

    /**
     * 购物车里面的每一个ID到真实的菜
     *
     * @param order
     * @return
     */
    public OrderItem filterOrderItemList(Order order, Long orderItemId) {
        return getList(order.getOrderItemDetailList()).stream().filter(p -> equals(orderItemId, p.getId())).collect(Collectors.toList()).get(0);
    }

    /**
     * 购物车里面的每一个ID到真实的菜
     *
     * @param order
     * @return
     */
    public Optional<OrderItem> filterOrderItemListOptional(Order order, Long orderItemId) {
        return getList(order.getOrderItemDetailList()).stream().filter(p -> equals(orderItemId, p.getId())).findFirst();
    }

    /**
     * 订单是否已经支付
     *
     * @param order
     * @return
     */
    public boolean isOrderPayed(Order order) {
        if (order == null) {
            logger.info("order is null");
            return false;
        }

        return getInt(order.getStatus()) == 100;
    }

    /**
     * 清空支付方式
     *
     * @param order
     */
    public void cleanPayType(Order order) {
        logger.info("clean the order {} pay type", order.getId());
        order.setPayType(null);
        order.setPayTypeBit(0);
    }

    /**
     * 是否所有的菜都已经checkout了
     *
     * @param order
     * @return
     */
    public boolean existCheckOut(Order order) {
        if (order == null) {
            logger.info("order is null");
            return false;
        }

        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());
        if (isEmpty(orderItemList)) {
            logger.info("orderItemList is empty");
            return false;
        }

        return orderItemList.stream().filter(p -> getBoolean(p.getCheckout()) || !getBoolean(p.getCustomerAdd())).findFirst().isPresent();
    }

    /**
     * 获取购物车里面的项
     *
     * @param order
     * @return
     */
    public List<OrderItem> getCardItemList(Order order) {
        if (order == null) {
            logger.info("order is null");
            return new ArrayList<>();
        }

        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());
        if (isEmpty(orderItemList)) {
            logger.info("order item list is empty");
            return orderItemList;
        }

        return orderItemList.stream().filter(p -> !getBoolean(p.getCheckout()) && getBoolean(p.getCustomerAdd())).collect(Collectors.toList());
    }

    /**
     * 清除购物车里面的项
     *
     * @param order
     */
    public void removeCardItem(Order order) {
        if (order == null) {
            logger.info("order is null");
            return;
        }

        List<OrderItem> cardItemList = getCardItemList(order);
        List<Long> cardItemIdList = cardItemList.stream().map(p -> p.getId()).collect(Collectors.toList());
        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());
        orderItemList = orderItemList.stream().filter(p -> !cardItemIdList.contains(p.getId().longValue())).collect(Collectors.toList());
        order.setOrderItemDetailList(orderItemList);
    }

    /**
     * 判断该会话是否已经锁定了钱或者菜
     *
     * @param lockOrderCashOrOrderItemList
     * @param sessionId
     * @return
     */
    public boolean isInTheCashLock(List<LockOrderCashOrOrderItem> lockOrderCashOrOrderItemList, String sessionId) {
        return lockOrderCashOrOrderItemList.stream().filter(p -> equals(p.getLockSessionId(), sessionId)).findAny().isPresent();
    }

    /**
     * 锁定钱
     *
     * @param orderInDb
     */
    public Double lockThePartCash(Order orderInDb) throws Exception {
        Long userId = ServletUtil.getUserId();
        PartPayService partPayService = PartPayService.getInstance();

        if (userId == null) {
            logger.info("c end lock the cash");
            return partPayService.assignPartPersonCashInC(orderInDb);
        } else {
            logger.info("b end lock the cash");
            return partPayService.assignPartPersonCashInB(orderInDb);
        }
    }

    /**
     * 锁定菜
     *
     * @param orderInDb
     * @param lockOrderCashOrOrderItemBo
     */
    public List<Long> lockTheOrderItem(Order orderInDb, LockOrderCashOrOrderItemBo lockOrderCashOrOrderItemBo) throws Exception {
        Long userId = ServletUtil.getUserId();
        if (userId == null) {
            logger.info("user is null");
            //清理过期的订单
            PartPayService.getInstance().filterExpireOrder(orderInDb);
            List<Long> otherUserLockItemIdList = PartPayService.getInstance().lockOrderItemInC(orderInDb, lockOrderCashOrOrderItemBo);

            //如果都是可以的，那么添加锁定
            if (isEmpty(otherUserLockItemIdList)) {
                if (orderInDb.getLockOrderCashOrOrderItemList() == null) {
                    orderInDb.setLockOrderCashOrOrderItemList(new ArrayList<>());
                }

                logger.info("user lock the {}", lockOrderCashOrOrderItemBo);
                List<LockOrderCashOrOrderItem> orderCashOrOrderItemList = getList(orderInDb.getLockOrderCashOrOrderItemList());

                //如果已经锁定了，不再重复添加,同样的菜不重复锁定
                if (!orderCashOrOrderItemList.stream().filter(p -> equals(p.getLockSessionId(), lockOrderCashOrOrderItemBo.getLockSessionId()) && !getBoolean(p.getPayed())).findFirst().isPresent()) {
                    logger.info("will add lock");
                    orderCashOrOrderItemList.add(lockOrderCashOrOrderItemBo);
                    commonService.save(orderInDb);
                }
            }

            return otherUserLockItemIdList;
        }

        logger.info("its b end");
        return new ArrayList<>();
    }

    /**
     * 发送到厨房之后，是否打印小票的判断
     *
     * @param orderInDb
     */
    public void sendToKitchenPrintWholeOrderInB(Order orderInDb, Long printerId, Boolean inB) throws Exception {
        logger.info("sendToKitchenPrintWholeOrderInB");

        if (orderInDb == null) {
            logger.info("orderInDb is null");
            return;
        }

        Long sceneId = orderInDb.getSceneId();
        Optional<Scene> sceneOptional = commonService.searchOneOptional(sceneId, Scene.class);
        if (!sceneOptional.isPresent()) {
            logger.info("can not find the scene id {}", sceneId);
            return;
        }

        if (getBoolean(inB)) {
            Scene scene = sceneOptional.get();
            if (!getBoolean(scene.getSendToKitchenAutoPrintOrderInB())) {
                logger.info("no need to printer the order");
                return;
            }
        } else {
            Scene scene = sceneOptional.get();
            if (!getBoolean(scene.getSendToKitchenAutoPrintOrderInC())) {
                logger.info("no need to printer the order");
                return;
            }
        }

        logger.info("begin to auto print");
        //这里需要自动发送
        Order printOrder = new Order();
        BeanUtils.copyProperties(orderInDb, printOrder);
        //B端添加的，或者C端落单的菜需要打印
        //如果开启c端落单审核，没同意落单的不打印
        List<OrderItem> orderItemList = getList(printOrder.getOrderItemDetailList()).stream().filter(p -> !getBoolean(p.getCustomerAdd()) || getBoolean(p.getCheckout())&&getBoolean(p.getConfirmItem())).collect(Collectors.toList());
        printOrder.setOrderItemDetailList(orderItemList);

        if (printerId != null) {
            logger.info("will printer the whole order when send some item to kitchen");
            PrinterService.getInstance().printOrder(printOrder, printerId, false, false);
            //打印订单，写入日志
            OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
            OrderOpLog orderOpLog = orderOpLogService.content(printOrder, PRINT_ORDER);
            orderOpLogService.printOrderLog(printOrder, orderOpLog);

        } else {
            logger.info("printer id is null");
        }
    }

    /**
     * 获取订单列表
     *
     * @param orderList
     * @return
     */
    public List<Long> getOrderIdList(List<Order> orderList) {
        return getList(orderList).stream().map(p -> p.getId()).collect(Collectors.toList());
    }

    /**
     * 查询父订单
     *
     * @param shopId
     * @param foodTableTemplateKey
     * @return
     */
    public List<Order> findOrderListByTemplateKey(Long shopId, String foodTableTemplateKey, Long sceneId) throws Exception {
        logger.info("food table template key is {}", foodTableTemplateKey);
        List<Order> orderList = findOrderByTemplateKey(shopId, foodTableTemplateKey);
        if (isEmpty(orderList)) {
            return new ArrayList<>();
        }

        //只要是同一个场景配置下面的订单，都算在该餐桌上面
        List<Scene> sceneList = SceneService.getInstance().findSameFoodConfigList(sceneId);
        List<Long> sceneIdList = sceneList.stream().map(s -> s.getId()).collect(Collectors.toList());
        sceneIdList.add(sceneId);

        logger.info("all table order size is {}, id is {}， sceneId list is {}", orderList.size(), logString(getOrderIdList(orderList)), logString(sceneIdList));
        //过滤父订单没有结束的订单
        orderList = orderList.stream().filter(order -> order.getParentOrderId() == null && !getBoolean(order.getCombineOrder()) && sceneIdList.contains(order.getSceneId().longValue()) && getInt(order.getStatus()) != ORDER_STATUS_END).collect(Collectors.toList());

        //再过滤该订单对应的订单还要存在的
        FoodTableService foodTableService = FoodTableService.getInstance();
        orderList = orderList.stream().filter(order -> {
            FoodTable foodTable = foodTableService.findFoodTableByUniqueCode(order.getShopId(), order.getUniqueCode());
            return foodTable != null && !getBoolean(foodTable.getFlagDelete());
        }).collect(Collectors.toList());

        return orderList;
    }

    /**
     * 通过餐桌号来查询未完成的订单列表
     *
     * @param shopId
     * @param foodTableTemplateKey
     * @return
     */
    public List<Order> findOrderByTemplateKey(Long shopId, String foodTableTemplateKey) throws Exception {
        Order order = new Order();
        order.setShopId(shopId);
        order.setFoodTableTemplateKey(foodTableTemplateKey);

        Shop shop = ShopService.getInstance().findShopById(shopId);
        //查询开店之后的所有订单
        order.setStartCreateTime(getLong(shop.getOpenTime()));
        logger.info("shop id is {} query food table template key is {} open time is {}", order.getShopId(), order.getFoodTableTemplateKey(), order.getStartCreateTime());
        return commonService.searchAll(order);
    }


    /**
     * 过滤已checkout的菜
     *
     * @param order
     */
    public void filterCheckoutOrderItem(Order order) {
        if (ServletUtil.isBEndPayOrder()) {
            List<OrderItem> orderItemList = getList(order.getOrderItemDetailList()).stream().filter(orderItem -> getBoolean(orderItem.getCheckout()) && getBoolean(orderItem.getConfirmItem())).collect(Collectors.toList());
            order.setOrderItemDetailList(orderItemList);
        } else {
            List<OrderItem> orderItemList = getList(order.getOrderItemDetailList()).stream().filter(orderItem -> getBoolean(orderItem.getCheckout())).collect(Collectors.toList());
            order.setOrderItemDetailList(orderItemList);
        }
    }

    /**
     * 锁定订单的支付方式
     *
     * @param order
     * @return
     */
    public int lockPayType(Order order) throws Exception {
        Order orderInDb = findOrder(order.getShopId(), order.getId());
        VerifyUtil.verify(() -> orderInDb.getParentOrderId() == null);

        if (getBoolean(orderInDb.getLockByWaiter())) {
            logger.info("lock by waiter");
            return LOCK_ORDER_PAY_TYPE_LOCKED_BY_WAITER;
        }

        //如果已经支付完成了，那么不能再进去了
        if (getInt(orderInDb.getStatus()) == ORDER_STATUS_END) {
            logger.info("order status end");
            return LOCK_ORDER_PAY_TYPE_FAILED;
        }

        //如果已经是分钱或者分菜结账了，那么其它人可以同时来操作了
        Integer userSelectPayType = getInt(orderInDb.getUserSelectPayType());

        if (Arrays.asList(USER_SELECT_PAY_TYPE_PART_FOOD, USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON).contains(userSelectPayType)) {
            logger.info("part pay already, pay type {}", userSelectPayType);
            return LOCK_ORDER_PAY_TYPE_OK;
        }

        //分钱结账锁定处理
        if (userSelectPayType == USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED && getInt(orderInDb.getStatus()) == ORDER_STATUS_PART_CASH_CUSTOMIZED) {
            logger.info("part pay customized already, pay type {}", userSelectPayType);
            return LOCK_ORDER_PAY_TYPE_OK;
        }

        String sessionId = ServletUtil.getSessionId();
        if (orderInDb.getPayTypeLock() == null) {
            PayTypeLock payTypeLock = new PayTypeLock();
            payTypeLock.setLockSessionId(sessionId);
            payTypeLock.setLockTime(System.currentTimeMillis());
            orderInDb.setPayTypeLock(payTypeLock);
            commonService.save(orderInDb);
            logger.info("payTypeLock {}", payTypeLock);
            return LOCK_ORDER_PAY_TYPE_OK;
        } else {
            PayTypeLock payTypeLock = orderInDb.getPayTypeLock();
            if (equals(payTypeLock.getLockSessionId(), sessionId)) {
                logger.info("same session Id, add lock time");
                payTypeLock.setLockTime(System.currentTimeMillis());
                commonService.save(orderInDb);
                return LOCK_ORDER_PAY_TYPE_OK;
            } else {
                logger.info("diff session id");

                if (System.currentTimeMillis() - payTypeLock.getLockTime() > Config.getInstance().getPayTypeLockTime()) {
                    logger.info("last lock time expired, current session id {}", sessionId);
                    payTypeLock.setLockSessionId(sessionId);
                    payTypeLock.setLockTime(System.currentTimeMillis());

                    //并且清空选择的支付方式,餐桌后付款场景,并且这里一定是一个人付款
                    if (!isOnlyOneUserCanPayInC(order)) {
                        orderInDb.setUserSelectPayType(null);
                        orderInDb.setStatus(ORDER_STATUS_STARTING);
                        orderInDb.setLockOrderCashOrOrderItemList(new ArrayList<>());
                    }

                    orderInDb.setPayTypeLock(payTypeLock);

                    commonService.save(orderInDb);
                    return LOCK_ORDER_PAY_TYPE_OK;
                } else {
                    logger.info("last lock session not expired");
                    return LOCK_ORDER_PAY_TYPE_FAILED;
                }
            }
        }
    }

    /**
     * 检查订单参数是否合法
     *
     * @param order
     */
    public void checkOrderParam(Order order) throws ResponseStatusException {
        Long shopId = order.getShopId();
        Long orderId = order.getId();
        VerifyUtil.verify(() -> shopId != null);
        VerifyUtil.verify(() -> orderId != null);
    }

    /**
     * 总二维的堂食或者外卖点餐
     *
     * @param parentOrder
     * @throws Exception
     */
    public void dealTakeOutOrder(Order parentOrder) throws Exception {
        Long shopId = parentOrder.getShopId();

        if (parentOrder.getTakeOutNumber() != null) {
            logger.info("the shop {} order {} has take out number {}", parentOrder.getShopId(), parentOrder.getId(), parentOrder.getTakeOutNumber());
            return;
        }

        //如果是外卖类的订单，添加提取唯一码
        if (getInt(parentOrder.getOrderType()) == Constant.ORDER_TYPE_TAKE_OUT || getInt(parentOrder.getOrderType()) == ORDER_TYPE_QUICK_FOOD) {
            addOrderNo(parentOrder);
            logger.info("will add take out number {}", parentOrder.getOrderNo());
            parentOrder.setTakeOutNumber(parentOrder.getOrderNo());
        }
    }

    /**
     * 判断该菜品是否已经被打印了
     *
     * @param orderInDb
     * @param orderItemId
     * @return
     */
    public boolean isOrderItemPrinted(Order orderInDb, Long orderItemId) {
        if (isEmpty(orderInDb.getSendPrinterList())) {
            logger.info("order send printer list is empty");
            return false;
        }

        if (orderItemId == null) {
            logger.info("order item id is null");
            return false;
        }

        List<Long> orderItemIdList = getList(orderInDb.getSendPrinterList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
        return orderItemIdList.contains(orderItemId.longValue());
    }

    /**
     * 获取子订单的支付方式，中英文
     *
     * @param order
     * @param zh
     * @return
     */
    public String getOrderPayType(Order order, Boolean zh) {
        Integer payTypeInt = order.getPayType();
        try {
            PayType payType = PayTypeService.getInstance().filterPayType(order.getShopId(), payTypeInt);
            if (zh == null || zh) {
                return payType.getName_zh();
            } else {
                return payType.getName_en();
            }
        } catch (Exception e) {
            logger.error("e", e);
            return "Unknown";
        }
    }

    /**
     * 加锁处理订单数据
     *
     * @param shopId
     * @param orderId
     * @param consumer
     */
    public void lockOrderAction(Long shopId, Long orderId, Function<Order, Boolean> consumer) throws Exception {
        //查询订单，并且修改订单
        OrderService orderService = OrderService.getInstance();
        String lockKey = orderService.getLockKey(shopId, orderId);
        logger.info("will action order {} {}", shopId, orderId);
        Object lock = localLockService.getLock(lockKey);

        synchronized (lock) {
            Order order = findOrder(shopId, orderId);
            Boolean apply = consumer.apply(order);

            if (getBoolean(apply)) {
                commonService.save(order);
            }
        }
    }

    /**
     * 是否只能是一个人结账的订单
     *
     * @param order
     * @return
     */
    public boolean isOnlyOneUserCanPayInC(Order order) throws Exception {
        Long shopId = order.getShopId();
        Long orderId = order.getId();

        Order orderInDb = findOrder(shopId, orderId);

        //不是餐桌的订单，那么一定只能一个人付款
        if (!isFoodTableOrder(orderInDb)) {
            logger.info("not food table order");
            return true;
        }

        //是餐桌的订单，那么必须要是先付款模式，才是一个人付款
        return getBoolean(orderInDb.getPayFirst());
    }

    /**
     * 固定餐桌订单处理，如果是支付完成，或者闭店的时候，需要处理
     *
     * @param order
     */
    public void resetFixOrder(Order order) throws Exception {
        Integer uniqueCode = foodTableService.openFoodTable(order.getShopId());
        order.setUniqueCode(uniqueCode);
        String foodTableKey = getFoodTableKey(order);
        order.setFoodTableKey(foodTableKey);
        commonService.save(order);
    }

    /**
     * 过滤出有锁定量，但是未发送到厨房的菜
     *
     * @param order
     * @return
     */
    public List<OrderItem> filterLockedOrderItem(Order order) {
        //只计算已落单的菜
        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList());
        List<Long> lockedOrderItemIdList = getList(order.getItemLockNumberList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
        List<Long> sendToKitchenOrderItemList = getList(order.getSendPrinterList()).stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());

        //先过滤已经锁定的菜
        orderItemList = orderItemList.stream().filter(p -> {
            return lockedOrderItemIdList.contains(p.getId().longValue());
        }).collect(Collectors.toList());

        //再过滤未发送到厨房的菜
        return orderItemList.stream().filter(p -> !sendToKitchenOrderItemList.contains(p.getId().longValue())).collect(Collectors.toList());
    }

    /**
     * 删除这段时间没有支付的子订单
     *
     * @param shopId
     * @param startTime
     * @param endTime
     */
    public void deleteUnpaySubOrder(Long shopId, Long startTime, Long endTime) throws Exception {
        Order order = new Order();
        order.setShopId(shopId);
        order.setStartCreateTime(startTime);
        order.setEndCreateTime(endTime);
        order.setParentOrder(false);
        order.setPayed(false);
        commonService.delete(order, false, null);
    }

    /**
     * 通过订单查询退款理由
     *
     * @param orderId
     * @return
     */
    public List<Reason> findReason(Long shopId, Long orderId) {
        Reason reason = new Reason();
        reason.setShopId(shopId);
        reason.setOrderId(orderId);
        return commonService.searchAll(reason);
    }

    /**
     * 判断是否是堂食订单
     *
     * @param order
     * @return
     */
    public boolean isTangOrder(Order order) {
        List<Integer> tangShiList = Arrays.asList(ORDER_TYPE_QUICK_FOOD, ORDER_TYPE_TANG_SHI);
        return tangShiList.contains(getInt(order.getOrderType()));
    }

    /**
     * 从一个订单里获取所有的主菜品ID，以方便菜品券做判断
     *
     * @param order
     * @return
     */
    public List<Long> getMainItemIdListFromOrder(Order order) {
        return getList(order.getOrderItemDetailList()).stream().map(orderItem -> {
            return orderItem.getMainItemId();
        }).collect(Collectors.toList());
    }

    /**
     * 从订单里面筛选出一个最低价格的菜出来
     *
     * @param orderItemList
     * @return
     */
    public Long filterLowestPriceOrderItem(List<OrderItem> orderItemList) {
        orderItemList.sort(Comparator.comparing(OrderItem::getBasePrice));
        return orderItemList.get(0).getId();
    }

    /**
     * 过滤出满足菜品券的菜
     *
     * @param order
     * @param discountTicket
     * @return
     */
    public List<OrderItem> filterOrderItem(Order order, DiscountTicket discountTicket) {
        return getList(order.getOrderItemDetailList()).stream().filter(orderItem -> {
            return getList(discountTicket.getMainItemIdList()).contains(getLong(orderItem.getMainItemId()).longValue());
        }).collect(Collectors.toList());
    }

    /**
     * 过滤出满足菜品券的菜同，计算打折费用的时候
     *
     * @param order
     * @param discountTicket
     * @return
     */
    public List<OrderItem> filterOrderItemInDiscount(Order order, DiscountTicket discountTicket) {
        return getList(order.getOrderItemDetailList()).stream().filter(orderItem -> {
            return getList(discountTicket.getMainItemIdList()).contains(getLong(orderItem.getMainItemId()).longValue()) && orderItem.getDiscountNumber() < orderItem.getCount();
        }).collect(Collectors.toList());
    }

    /**
     * 获取订单里面使用的优惠券
     *
     * @param order
     * @return
     */
    public List<String> getOrderTicketCodeList(Order order) {
        List<String> codeList = new ArrayList<>();

        List<String> parentTicketCodeList = order.getParentTicketCodeList();
        if (isNotEmpty(parentTicketCodeList)) {
            codeList.addAll(parentTicketCodeList);
        }

        List<String> ticketCodeList = order.getTicketCodeList();
        if (isNotEmpty(ticketCodeList)) {
            codeList.addAll(ticketCodeList);
        }

        return new ArrayList<>(new HashSet<>(codeList));
    }

    /**
     * 获取优惠券列表
     *
     * @param order
     * @return
     */
    public List<String> getCodeList(Order order) {
        return getOrderTicketCodeList(order);
    }


    /**
     * 查询固定餐桌二维码
     *
     * @param shopId
     * @param tableRow
     * @param tableColumn
     * @return
     * @throws Exception
     */
    public Order searchFixOrder(Long shopId, Integer tableRow, Integer tableColumn, GlobalSetting globalSetting) throws Exception {
        Shop shop = ShopService.getInstance().findShopById(shopId);

        Order order = new Order();
        order.setShopId(shopId);
        order.setStartCreateTime(shop.getOpenTime());
        order.setUniqueCode(0);
        order.setTableRow(tableRow);
        order.setTableColumn(tableColumn);
        order.setStartCreateTime(shop.getOpenTime());
        order.setParentOrder(true);
        order.setSortField(new String[]{"createTime"});
        order.setSortType("DESC");

        List<Order> orderList = commonService.searchList(order);
        if (isEmpty(orderList)) {
            return null;
        }

        //并且没有结束的订单
        orderList = orderList.stream().filter(o -> getInt(o.getStatus()) != ORDER_STATUS_END).collect(Collectors.toList());

        if (isEmpty(orderList)) {
            return null;
        }

        orderList.forEach(o -> dealCustomerShow(o, globalSetting));

        orderList = orderList.stream().filter(o -> o.getCustomerShow()).collect(Collectors.toList());

        if (isEmpty(orderList)) {
            return null;
        }

        logger.info("get the fix order {}", orderList.get(0).getId());
        return orderList.get(0);
    }

    /**
     * 创建固定餐桌订单
     *
     * @param shopId
     * @param tableRow
     * @param tableColumn
     * @return
     */
    public Order createFixOrder(Long shopId, Integer tableRow, Integer tableColumn) throws Exception {
        Order order = new Order();
        order.setShopId(shopId);
        order.setTableRow(tableRow);
        order.setTableColumn(tableColumn);
        order.setUniqueCode(0);
        order.setCustomerShow(true);
        order.setDefaultFoodTableOrder(true);
        order.setOrderType(ORDER_TYPE_TANG_SHI);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        orderDefaultValue(order, shop);

        //查询场景值
        Scene theMatchScene = SceneService.getInstance().findTheMatchScene(shopId);
        order.setSceneId(theMatchScene.getId());

        return new CreateOrderChain().createOrder(order);
    }

    /**
     * 获取哪些菜已经发送到了厨房
     *
     * @param order
     * @return
     */
    public List<Long> getSendKitchenList(Order order) {
        if (order == null) {
            return new ArrayList<>();
        }

        if (isEmpty(order.getSendPrinterList())) {
            return new ArrayList<>();
        }

        List<SendPrinter> sendPrinterList = order.getSendPrinterList();
        return sendPrinterList.stream().map(p -> p.getOrderItemId()).collect(Collectors.toList());
    }

    /**
     * 处理C端是否能够显示
     *
     * @param order
     * @return
     */
    public void dealCustomerShow(Order order, GlobalSetting globalSetting) {
        //还没有支付，那么可以显示
        if (order.getPayEndTime() == null) {
            order.setCustomerShow(true);
            return;
        }

        Long payEndTime = order.getPayEndTime();
        long currentTimeMillis = System.currentTimeMillis();
        commonService.setDefaultValue(globalSetting);

        long disableTime = 0L;

        //固定餐桌二维码
        if (getInt(order.getUniqueCode()) == 0) {
            if (getBoolean(order.getPayFirst())) {
                disableTime = globalSetting.getQrCodeOnDeskDisablePayFirst();
            } else {
                disableTime = globalSetting.getQrCodeOnDeskDisablePayAfter();
            }
        } else {
            if (getBoolean(order.getPayFirst())) {
                disableTime = globalSetting.getQrCodeDisableAddNewOrderPayFirst();
            } else {
                disableTime = globalSetting.getQrCodeDisableAddNewOrderPayAfter();
            }
        }

        order.setCustomerShow(payEndTime + disableTime * DateUtil.ONE_MINUTE > currentTimeMillis);
    }

    /**
     * 根据父订单，创建一个子订单
     *
     * @param order
     * @return
     */
    public Order createSubOrder(Order order) throws Exception {
        Order subOrder = createPayOrder(order);
        subOrder.setSubOrder(true);

        //清空服务费，消费税，外卖折扣
        subOrder.setServiceFee(null);
        subOrder.setConsumptionTax(null);
        subOrder.setTakeOutDiscountFee(null);

        //只有服务员端才产生序列号
        if (ServletUtil.getUserId() != null && Arrays.asList(USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON, USER_SELECT_PAY_TYPE_PART_FOOD, USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED).contains(getInt(order.getUserSelectPayType()))) {
            //设置序列号
            List<Order> subOrderList = findAllSubOrders(order.getShopId(), order.getId());
            if (subOrderList.isEmpty()) {
                subOrder.setSubOrderId(1);
            } else {
                int maxSubOrderId = subOrderList.stream().mapToInt(p -> p.getSubOrderId()).max().getAsInt();
                subOrder.setSubOrderId(maxSubOrderId + 1);
            }
        }

        logger.info("will create sub order {}  {} index {}", order.getShopId(), order.getId(), subOrder.getSubOrderId());

        return subOrder;
    }

    /**
     * 查询所有的子订单
     *
     * @param shopId
     * @param orderId
     * @return
     */
    public List<Order> findAllSubOrders(Long shopId, Long orderId) {
        Order order = new Order();
        order.setShopId(shopId);
        order.setParentOrderId(orderId);
        order.setSubOrder(true);
        return commonService.searchAll(order);
    }

    /**
     * 删除子订单
     *
     * @param orderInDb
     */
    public void deleteSubOrder(Order orderInDb) throws Exception {
        if (!getBoolean(orderInDb.getSubOrder())) {
            logger.info("is not sub order");
            return;
        }

        logger.info("its delete sub order {}", orderInDb.getId());

        //已经付款的订单不能删除
        VerifyUtil.verify(() -> !getBoolean(orderInDb.getPayed()), ORDER_PAYED_CAN_NOT_DELETE);

        List<Order> allSubOrderList = findAllSubOrders(orderInDb.getShopId(), orderInDb.getParentOrderId());
        long unpaidOrder = allSubOrderList.stream().filter(p -> !getBoolean(p.getPayed())).count();

        //分菜结账必须保留一个
        if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_FOOD) {
            //至少保留一个子订单
            VerifyUtil.verify(() -> unpaidOrder > 1, AT_LEAST_KEEP_ONE_ORDER);
            commonService.delete(orderInDb);

            //找到没有删除的单，并且不是当前单，并且是单号最小的单
            List<Order> orderList = allSubOrderList.stream().filter(p -> !getBoolean(p.getPayed())).filter(p -> !equals(p.getId(), orderInDb.getId())).sorted(Comparator.comparing(Order::getSubOrderId)).collect(Collectors.toList());
            Order firstOrder = orderList.get(0);

            logger.info("will move item to order {}", firstOrder.getId());

            firstOrder.getOrderItemDetailList().addAll(orderInDb.getOrderItemDetailList());
            calPriceForB_C_END(firstOrder);
            commonService.save(firstOrder);

            return;
        } else if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_FOOD) {
            //自定义分钱结账不做子订单的个数判断
        } else if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON) {
            VerifyUtil.throwError(AT_LEAST_KEEP_ONE_ORDER);
        } else if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED) {
            logger.info("delete customized order");
            commonService.delete(orderInDb);

            //将分配金额加回去
            Order parentOrder = findOrder(orderInDb.getShopId(), orderInDb.getParentOrderId());
            parentOrder.setUnassignCash(showMoneyDouble(parentOrder.getUnassignCash() + orderInDb.getUserCost()));
            commonService.save(parentOrder);
        } else {
            logger.info("do not config the right pay type");
            VerifyUtil.throwError(CONFIG_WRONG);
        }
    }

    /**
     * 通过子订单查询支付订单
     *
     * @return
     */
    public List<Order> findPayOrderWithSubOrderId(Order subOrder) {
        Order order = new Order();
        order.setShopId(subOrder.getShopId());
        order.setRelatedSubOrderId(subOrder.getId());
        return commonService.searchAll(order);
    }

    /**
     * 添加子订单
     *
     * @param orderInDb
     */
    public void addSubOrders(Order orderInDb) throws Exception {
        orderInDb.setLockByWaiter(true);
        Long shopId = orderInDb.getShopId();
        Long orderId = orderInDb.getId();

        //依次将菜删除掉，然后创建一个新的子订单
        Order cloneOrder = (Order) ClassUtil.clone(orderInDb);

        //判断有哪些已经支付的订单
        if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_FOOD) {
            List<Order> allSubOrderList = findAllSubOrders(shopId, orderId);
            for (Order subOrder : allSubOrderList) {
                List<OrderItem> orderItemDetailList = subOrder.getOrderItemDetailList();
                List<OrderItem> parentOrderItemDetailList = cloneOrder.getOrderItemDetailList();

                for (OrderItem orderItemInSubOrder : orderItemDetailList) {
                    Optional<OrderItem> orderItemOptional = parentOrderItemDetailList.stream().filter(p -> equals(p.getId(), orderItemInSubOrder.getId())).findAny();
                    if (orderItemOptional.isPresent()) {
                        OrderItem findOrderItem = orderItemOptional.get();
                        if (findOrderItem.getCount() - orderItemInSubOrder.getCount() <= 0) {
                            logger.info("will remove the order item, {}", findOrderItem.getId());
                            //这里不能直接移除，因为重写了equals方法
                            List<OrderItem> orderItemList = parentOrderItemDetailList.stream().filter(p -> !equals(p.getId(), findOrderItem.getId())).collect(Collectors.toList());
                            parentOrderItemDetailList = orderItemList;
                            cloneOrder.setOrderItemDetailList(orderItemList);
                        } else {
                            int count = findOrderItem.getCount() - orderItemInSubOrder.getCount();
                            //只是减少数量
                            logger.info("cut the order item {} to {}", findOrderItem.getId(), count);
                            findOrderItem.setCount(count);
                        }
                    } else {
                        logger.info("do not find the order item {}, order id {}", orderItemInSubOrder.getId(), subOrder.getId());
                    }
                }
            }

            //有菜的时候才新创建订单
            if (isNotEmpty(cloneOrder.getOrderItemDetailList())) {
                Order subOrder = createSubOrder(orderInDb);
                subOrder.setOrderItemDetailList(new ArrayList<>());

                //最后将订单里面的菜展开
                for (OrderItem orderItem : cloneOrder.getOrderItemDetailList()) {
                    //依次添加菜
                    for (Integer i = 0; i < orderItem.getCount(); i++) {
                        OrderItem cloneOrderItem = (OrderItem) ClassUtil.clone(orderItem);
                        cloneOrderItem.setCount(1);
                        subOrder.getOrderItemDetailList().add(cloneOrderItem);
                        logger.info("end add order item {} to order {}", cloneOrderItem.getId(), subOrder.getId());
                    }
                }

                commonService.save(subOrder);
            }
        } else if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED) {
            //自定义分钱，不用新增子订单
            logger.info("customized order , no need add new order");
        } else if (getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON) {
            //查看还有几个单没有分配，然后再创建几个单，最后一个单需要用剩余金额来处理
            List<Order> allSubOrderList = findAllSubOrders(shopId, orderId);

            //均摊税费
            showPrice(orderInDb, ServletUtil.getUserId() != null);
            Double consumptionTax = getDouble(orderInDb.getConsumptionTax());
            double perConsumptionTax = showMoneyDouble(consumptionTax / orderInDb.getPartCash().getPersons());

            //人数不够
            if (allSubOrderList.size() < orderInDb.getPartCash().getPersons()) {
                int leftSubOrderSize = orderInDb.getPartCash().getPersons() - allSubOrderList.size();
                Integer persons = orderInDb.getPartCash().getPersons();

                //分配的钱
                double assignCash = allSubOrderList.stream().mapToDouble(p -> showMoneyDouble(p.getUserCost())).sum();
                double assignTax = allSubOrderList.stream().mapToDouble(p -> showMoneyDouble(p.getConsumptionTax())).sum();

                for (Integer i = 0; i < leftSubOrderSize; i++) {
                    if (i < leftSubOrderSize - 1) {
                        Order subOrder = createSubOrder(orderInDb);
                        //修改订单列表
                        List<OrderItem> orderItemList = getOrderItemList(subOrder);
                        subOrder.setOrderItemDetailList(orderItemList);

                        Double userCost = showMoneyDouble(orderInDb.getUserCost() / persons);
                        subOrder.setUserCost(userCost);
                        subOrder.setUserCost_b(userCost);
                        subOrder.setUserCost_c(userCost);
                        subOrder.setCostOrigin(subOrder.getUserCost());
                        subOrder.setCostOrigin_b(subOrder.getUserCost_b());
                        subOrder.setCostOrigin_c(subOrder.getUserCost());

                        subOrder.setServiceFee(null);
                        subOrder.setServiceFee_b(null);
                        subOrder.setServiceFee_c(null);

                        subOrder.setConsumptionTax_b(perConsumptionTax);
                        subOrder.setConsumptionTax_c(perConsumptionTax);
                        subOrder.setConsumptionTax(perConsumptionTax);
                        //这里是创建，不是更新
                        commonService.directSave(subOrder);
                        //创建子订单，写入日志
                        OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
                        OrderOpLog orderOpLog = orderOpLogService.content(subOrder, CREATE_ORDER);
                        orderOpLogService.createOrderLog(subOrder, orderOpLog);

                        assignCash = assignCash + userCost;
                        assignTax = assignTax + perConsumptionTax;
                        continue;
                    }

                    //最后一个
                    if (i == leftSubOrderSize - 1) {
                        Order subOrder = createSubOrder(orderInDb);
                        //修改订单列表
                        List<OrderItem> orderItemList = getOrderItemList(subOrder);
                        subOrder.setOrderItemDetailList(orderItemList);

                        subOrder.setUserCost(showMoneyDouble(orderInDb.getUserCost() - assignCash));
                        subOrder.setUserCost_b(subOrder.getUserCost());
                        subOrder.setUserCost_c(subOrder.getUserCost());

                        subOrder.setCostOrigin(subOrder.getUserCost());
                        subOrder.setCostOrigin_b(subOrder.getCostOrigin());
                        subOrder.setCostOrigin_c(subOrder.getCostOrigin());

                        subOrder.setServiceFee(null);
                        subOrder.setServiceFee_b(null);
                        subOrder.setServiceFee_c(null);

                        //计算税
                        double leftTax = showMoneyDouble(getDouble(orderInDb.getConsumptionTax()) - assignTax);

                        subOrder.setConsumptionTax_b(leftTax);
                        subOrder.setConsumptionTax_c(leftTax);
                        subOrder.setConsumptionTax(leftTax);

                        logger.info("the last order , and user cost is {}", subOrder.getUserCost());
                        //这里是创建，不是更新
                        commonService.directSave(subOrder);
                        //创建子订单，写入日志
                        OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
                        OrderOpLog orderOpLog = orderOpLogService.content(subOrder, CREATE_ORDER);
                        orderOpLogService.createOrderLog(subOrder, orderOpLog);

                    }
                }
            }
        }

        commonService.save(orderInDb);
    }

    /**
     * 订单是否可以结账
     *
     * @param order
     * @return
     */
    public boolean orderCanCheckout(Order order) {
        if (order == null) {
            return false;
        }

        //计算订单是否可以在B端显示结账按钮
        //可以在B端显示，并且有已经落单的菜
        if (getBoolean(order.getBusinessEndShow()) && isNotEmpty(getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList()))) {
            return true;
        }

        return false;

    }

    /**
     * @return
     */
    public Optional<Order> findOrderByUniqueCode(Long shopId, Integer uniqueCode) {
        Order order = new Order();
        order.setShopId(shopId);
        order.setUniqueCode(uniqueCode);
        return commonService.searchOneOptional(order);
    }

    /**
     * 获取没有发送到厨房里面的菜的列表
     *
     * @param order
     * @param orderInDb
     * @return
     */
    public List<OrderItem> getNotSendToKitchenOrderItemList(Order order, Order orderInDb) {
        List<Long> orderItemIdList = toOrderItemIdList(order.getOrderItemDetailList());

        List<Long> sendKitchenList = getSendKitchenList(orderInDb);
        orderItemIdList = orderItemIdList.stream().filter(orderItemId -> !sendKitchenList.contains(orderItemId)).collect(Collectors.toList());
        return filterOrderItemList(orderInDb, orderItemIdList);
    }

    /**
     * 过滤出没有在审核列表里面的菜
     *
     * @param order
     * @return
     */
    public List<OrderItem> filterNotAuditItemList(Order order) {
        Long shopId = order.getShopId();
        Long orderId = order.getId();
        SendToKitchenAudit sendToKitchenAudit = new SendToKitchenAudit();
        sendToKitchenAudit.setShopId(shopId);
        sendToKitchenAudit.setOrderId(orderId);

        List<SendToKitchenAudit> sendToKitchenAuditList = commonService.searchAll(sendToKitchenAudit);

        if (isEmpty(sendToKitchenAuditList)) {
            logger.info("send to kitchen list is empty order id {} ", orderId);
            return order.getOrderItemDetailList();
        }


        List<OrderItem> auditOrderItemList = sendToKitchenAuditList.stream().flatMap(p -> p.getOrderItemDetailList().stream()).collect(Collectors.toList());
        List<Long> auditOrderItemIdList = toOrderItemIdList(auditOrderItemList);
        List<Long> itemIdList = toOrderItemIdList(order.getOrderItemDetailList());
        itemIdList = itemIdList.stream().filter(orderItemId -> !auditOrderItemIdList.contains(orderItemId.longValue())).collect(Collectors.toList());
        return filterOrderItemList(order, itemIdList);
    }

    /**
     * 根据当前的生成订单来产生一个落单审核
     *
     * @param order
     */
    public void generateSendToKitchenAudit(Order order, Order orderInDb) throws Exception {
        //只处理没有发送到厨房里面的菜
        List<OrderItem> orderItemList = filterNotAuditItemList(order);
        if (isEmpty(orderItemList)) {
            logger.info("nothing order item can be send to audit");
            return;
        }

        order.setOrderItemDetailList(orderItemList);

        PriceResult priceResult = calPrice(order);
        Double price = priceResult.getPrice();
        logger.info("price result is {}", JSONObject.toJSON(priceResult));
        SendToKitchenAudit sendToKitchenAudit = new SendToKitchenAudit();
        sendToKitchenAudit.setOrderId(order.getId());
        sendToKitchenAudit.setShopId(order.getShopId());
        sendToKitchenAudit.setOrderItemDetailList(order.getOrderItemDetailList());
        sendToKitchenAudit.setStatus(0);
        sendToKitchenAudit.setOrderNo(orderInDb.getOrderNo());
        sendToKitchenAudit.setCash(price);
        sendToKitchenAudit.setContact(orderInDb.getContact());
        sendToKitchenAudit.setCode(orderInDb.getCode());
        sendToKitchenAudit.setOrderType(orderInDb.getOrderType());
        commonService.createObject(sendToKitchenAudit);
    }

    /**
     * 查询当前分店有多少待确认的单
     *
     * @param shopId
     * @return
     */
    public int countConfirmOrder(Long shopId) {
        SendToKitchenAudit sendToKitchenAudit = new SendToKitchenAudit();
        sendToKitchenAudit.setShopId(shopId);
        sendToKitchenAudit.setStatus(0);
        Long count = commonService.count(sendToKitchenAudit);
        return count.intValue();
    }

    /**
     * 确认订单
     *
     * @param order
     */
    public void confirmOrder(Order order, Order orderInDb) throws Exception {
        List<OrderItem> orderItemDetailListInDb = getList(orderInDb.getOrderItemDetailList());
        List<Long> orderItemIdList = toOrderItemIdList(order.getOrderItemDetailList());

        List<Long> sendKitchenList = getSendKitchenList(orderInDb);

        //已经落单的，不再重复落单
        orderItemIdList = orderItemIdList.stream().filter(orderItemId -> !sendKitchenList.contains(orderItemId.longValue())).collect(Collectors.toList());

        if (isEmpty(orderItemIdList)) {
            logger.info("the item id list is confirmed before");
            return;
        }

        //场景没有切换，余量也是够的,还没有设置过落单时间，那么添加落单时间
        if (orderInDb.getConfirmTime() == null) {
            orderInDb.setConfirmTime(System.currentTimeMillis());
            logger.info("add the confirm time is {}", orderInDb.getConfirmTime());
        }


        //将这些菜修改成已确认
        List<OrderItem> orderItemList = filterOrderItemList(orderInDb, toOrderItemIdList(order.getOrderItemDetailList()));
        logger.info("order item list size is {}", orderItemList.size());
        orderItemList.forEach(p -> p.setConfirmItem(true));
        //计算一下订单的价格
        calPriceForB_C_END(orderInDb);
        commonService.save(orderInDb);

        //将C端的菜品修改成正在结算
        for (OrderItem orderItem : getList(order.getOrderItemDetailList())) {
            Optional<OrderItem> orderItemOptional = orderItemDetailListInDb.stream().filter(p -> equals(p.getId(), orderItem.getId())).findAny();
            if (orderItemOptional.isPresent()) {
                OrderItem orderItemInDb = orderItemOptional.get();
                logger.info("will set order item {} to checkout", orderItemInDb.getId());
                orderItemOptional.get().setCheckout(true);
                orderItemOptional.get().setConfirmItem(true);
            } else {
                logger.info("can not find the order item {}", orderItem.getId());
            }
        }

        //如果没有订单号，添加订单号
        if (orderInDb.getOrderNo() == null) {
            addOrderNo(orderInDb);
        }

        DayReportService.getInstance().addSendKitchenNumber(orderInDb, orderItemIdList);

        PrinterService.getInstance().printerOrderItemList(orderInDb, orderItemIdList);

        //添加发送到厨房列表
        List<SendPrinter> sendPrinterList = getList(orderItemIdList).stream().map(orderItemId -> {
            SendPrinter sendPrinter = new SendPrinter();
            sendPrinter.setOrderItemId(orderItemId);
            return sendPrinter;
        }).collect(Collectors.toList());

        logger.info("send printer list is {}", StringUtils.join(sendPrinterList, ","));
        //如果以前发送过的，后面的再加粗，本次只是添加发送到厨房的列表到数据库
        for (SendPrinter sendPrinter : sendPrinterList) {
            logger.info("send flag is {}", sendPrinter);
            sendPrinter(orderInDb, sendPrinter);
        }

        //在B端可见
        orderInDb.setBusinessEndShow(true);
        //订单添加标记，说明已经发送到厨房了
        orderInDb.setSendKitchen(true);

        commonService.save(orderInDb);

        //同时修改餐桌状态
        FoodTableService.getInstance().dealOrderFoodTableStatus(orderInDb);
    }

    /**
     * 检查项再转成订单
     *
     * @param sendToKitchenAudit
     * @return
     */
    public Order sendToKitchenAuditToOrder(SendToKitchenAudit sendToKitchenAudit) {
        Order order = new Order();
        order.setShopId(sendToKitchenAudit.getShopId());
        order.setId(sendToKitchenAudit.getOrderId());
        order.setOrderItemDetailList(sendToKitchenAudit.getOrderItemDetailList());
        return order;
    }

    /**
     * 计算订单在B端，C端的显示
     *
     * @param order
     * @throws Exception
     */
    public void calPriceForB_C_END(Order order) throws Exception {
        long startTime = System.currentTimeMillis();
        //计算C端，B端两个价格
        {
            List<OrderItem> orderItemListInC = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
            Order cloneOrder = (Order) ClassUtil.clone(order);
            cloneOrder.setOrderItemDetailList(orderItemListInC);
            PriceResult priceResult = calPriceFilterOrderItem(cloneOrder);
            order.setUserCost(priceResult.getPrice());
            order.setUserCost_c(priceResult.getPrice());
            order.setCostOrigin_c(priceResult.getCostOrigin());
            order.setTakeOutDiscountFee_c(cloneOrder.getTakeOutDiscountFee());
            order.setServiceFee_c(priceResult.getServiceFee());
            order.setLeft_cash_c(cloneOrder.getLeftCash());
            order.setConsumptionTax_c(cloneOrder.getConsumptionTax());
            order.setPackageFee(cloneOrder.getPackageFee());
        }

        {
            List<OrderItem> orderItemListInB = order.getOrderItemDetailList().stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList());
            Order cloneOrder = (Order) ClassUtil.clone(order);
            cloneOrder.setOrderItemDetailList(orderItemListInB);
            PriceResult priceResult = calPriceFilterOrderItem(cloneOrder);
            order.setUserCost(priceResult.getPrice());
            order.setUserCost_b(priceResult.getPrice());
            order.setCostOrigin_b(priceResult.getCostOrigin());
            order.setTakeOutDiscountFee_b(cloneOrder.getTakeOutDiscountFee());
            order.setServiceFee_b(priceResult.getServiceFee());
            order.setLeft_cash_b(cloneOrder.getLeftCash());
            order.setConsumptionTax_b(cloneOrder.getConsumptionTax());
            order.setPackageFee(cloneOrder.getPackageFee());
        }

        showPrice(order, null);
        logger.info("cal price for b and c end, costTime {}", System.currentTimeMillis() - startTime);
    }

    /**
     * 删除掉落单审核
     *
     * @param shopId
     */
    public void deleteSendToKitchen(Long shopId) throws Exception {
        SendToKitchenAudit sendToKitchenAudit = new SendToKitchenAudit();
        sendToKitchenAudit.setShopId(shopId);
        commonService.delete(sendToKitchenAudit, false);
    }

    /**
     * 查询落单审核
     *
     * @param shopId
     * @param orderId
     * @return
     */
    public List<SendToKitchenAudit> findSendToKitchenAudit(Long shopId, Long orderId) {
        SendToKitchenAudit sendToKitchenAudit = new SendToKitchenAudit();
        sendToKitchenAudit.setShopId(shopId);
        sendToKitchenAudit.setOrderId(orderId);
        return commonService.searchAll(sendToKitchenAudit);
    }

    /**
     * 确认一个落单结果
     *
     * @param sendToKitchenAuditInDb
     * @throws Exception
     */
    public void confirm(SendToKitchenAudit sendToKitchenAuditInDb) throws Exception {
        logger.info("confirm the order {}", sendToKitchenAuditInDb.getShopId());
        Order order = sendToKitchenAuditToOrder(sendToKitchenAuditInDb);
        Order orderInDb = findOrder(order.getShopId(), order.getId());
        confirmOrder(order, orderInDb);
    }

    /**
     * 重新计算价格并保存
     *
     * @param sendToKitchenAuditInDb
     */
    public void calPriceAndSave_b_c(SendToKitchenAudit sendToKitchenAuditInDb) throws Exception {
        Long shopId = sendToKitchenAuditInDb.getShopId();
        Long orderId = sendToKitchenAuditInDb.getOrderId();
        Order order = findOrder(shopId, orderId);
        calPriceForB_C_END(order);
        commonService.save(order);
    }

    /**
     * 删除订单相关的所有落单审核
     *
     * @param orderInDb
     */
    public void deleteAllAuditWithOrder(Order orderInDb) {
        List<SendToKitchenAudit> sendToKitchenAuditList = findSendToKitchenAudit(orderInDb.getShopId(), orderInDb.getId());
        sendToKitchenAuditList = sendToKitchenAuditList.stream().filter(p -> p.getStatus() == 0).collect(Collectors.toList());
        sendToKitchenAuditList.forEach(s -> {
            try {
                s.setFlagDelete(true);
                commonService.save(s);
            } catch (Exception e) {
                logger.error("e", e);
            }
        });
    }

    /**
     * 处理订单价格显示
     *
     * @param orderInDb
     * @param bEndRequest
     */
    public void showPrice(Order orderInDb, Boolean bEndRequest) {
        if (bEndRequest == null) {
            bEndRequest = ServletUtil.getUserId() != null;
        }

        //分别显示B端，C端的价格显示
        if (bEndRequest) {
            orderInDb.setUserCost(orderInDb.getUserCost_b());
            orderInDb.setUserCostLong(showMoneyDouble(getDouble(orderInDb.getUserCost()) * 100).longValue());
            orderInDb.setCostOrigin(orderInDb.getCostOrigin_b());
            orderInDb.setTakeOutDiscountFee(orderInDb.getTakeOutDiscountFee_b());
            orderInDb.setServiceFee(orderInDb.getServiceFee_b());

            //如果支付没有开始的时候，剩余金额以及未分配金额有两个，已经开始支付的时候，金额就只有一个了
            if (orderInDb.getStatus() == null || orderInDb.getStatus() == ORDER_STATUS_STARTING) {
                orderInDb.setLeftCash(orderInDb.getLeft_cash_b());
                orderInDb.setUnassignCash(orderInDb.getUserCost());
            }

            orderInDb.setConsumptionTax(orderInDb.getConsumptionTax_b());
        } else {
            orderInDb.setUserCost(orderInDb.getUserCost_c());
            orderInDb.setUserCostLong(showMoneyDouble(getDouble(orderInDb.getUserCost()) * 100).longValue());
            orderInDb.setCostOrigin(orderInDb.getCostOrigin_c());
            orderInDb.setTakeOutDiscountFee(orderInDb.getTakeOutDiscountFee_c());
            orderInDb.setServiceFee(orderInDb.getServiceFee_c());
            //如果支付没有开始的时候，剩余金额以及未分配金额有两个，已经开始支付的时候，金额就只有一个了
            if (orderInDb.getStatus() == null || orderInDb.getStatus() == ORDER_STATUS_STARTING) {
                orderInDb.setLeftCash(orderInDb.getLeft_cash_c());
                orderInDb.setUnassignCash(orderInDb.getUserCost());
            }

            orderInDb.setConsumptionTax(orderInDb.getConsumptionTax_c());
        }

        logger.info("not order user cost is {}, cost origin is {}, take out discount fee {}, service fee {}, left cash {}, unassign cash {}", orderInDb.getUserCost(), orderInDb.getCostOrigin(), orderInDb.getTakeOutDiscountFee(), orderInDb.getServiceFee(), orderInDb.getLeftCash(), orderInDb.getUnassignCash());
    }

    /**
     * 是否是C端的支付，C端的支付目前都是回调类型的支付
     *
     * @return
     */
    public boolean customerEndPay() {
        return ServletUtil.getUserId() == null;
    }

    /**
     * 给订单添加单号,如果单号不存在
     *
     * @param order
     */
    public void addOrderNo(Order order) throws Exception {
        if (order.getOrderNo() != null) {
            return;
        }

        Integer orderNo = createOrderNo(order.getShopId());
        order.setOrderNo(orderNo);
    }

    /**
     * 落单审核拒绝
     *
     * @param orderInDb
     * @param sendToKitchenAuditInDb
     */
    public void rejectAudit(Order orderInDb, SendToKitchenAudit sendToKitchenAuditInDb) throws Exception {
        //这次是拒绝，那么需要处理下锁定量，将锁定量回退
        logger.info("reject the confirm");

        //这里需要将订单里面的菜删除掉
        List<OrderItem> orderItemDetailList = sendToKitchenAuditInDb.getOrderItemDetailList();
        List<Long> orderItemIdList = toOrderItemIdList(orderItemDetailList);
        List<OrderItem> leftOrderItemList = getList(orderInDb.getOrderItemDetailList()).stream().filter(p -> !orderItemIdList.contains(p.getId().longValue())).collect(Collectors.toList());
        orderInDb.setOrderItemDetailList(leftOrderItemList);

        //重新计算价格
        calPriceForB_C_END(orderInDb);
    }

    /**
     * 获取订单里面的菜的列表
     *
     * @param order
     * @return
     */
    public List<OrderItem> getOrderItemList(Order order) {
        Long userId = ServletUtil.getUserId();
        if (userId != null) {
            //B端
            return getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getCheckout()) && getBoolean(p.getConfirmItem())).collect(Collectors.toList());
        } else {
            //C端
            return getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getCheckout())).collect(Collectors.toList());
        }
    }

    /**
     * 打印小票，落单的时候
     *
     * @param orderInDb
     * @throws Exception
     */
    public void printOrderTipsSendToKitchen(Order orderInDb) throws Exception {
        List<Printer> printerList = ShopService.getInstance().findPrinterList(orderInDb.getShopId());
        Optional<Printer> printerOptional = printerList.stream().filter(p -> getBoolean(p.getPrintOrderInC())).findFirst();

        if (printerOptional.isPresent()) {
            logger.info("will print the whole order");
            sendToKitchenPrintWholeOrderInB(orderInDb, printerOptional.get().getId(), false);
        } else {
            logger.info("no need to print whole order");
        }
    }

    /**
     * 过滤优惠券与折扣的关系
     *
     * @param ticketDiscountFeeList
     * @param code
     * @return
     */
    public TicketDiscountFee filterTicketDiscountFee(List<TicketDiscountFee> ticketDiscountFeeList, String code) {
        if (ticketDiscountFeeList == null) {
            logger.info("old data");
            return null;
        }

        Optional<TicketDiscountFee> ticketDiscountFeeOptional = ticketDiscountFeeList.stream().filter(ticketDiscountFee -> ticketDiscountFee.getCode().equals(code)).findAny();
        if (ticketDiscountFeeOptional.isPresent()) {
            return ticketDiscountFeeOptional.get();
        }

        TicketDiscountFee ticketDiscountFee = new TicketDiscountFee(code);
        ticketDiscountFeeList.add(ticketDiscountFee);
        return ticketDiscountFee;
    }

    /**
     * 添加优惠券的费用
     *
     * @param ticketDiscountFeeList
     * @param code
     * @param fee
     */
    public void addTicketDiscountFeePrice(List<TicketDiscountFee> ticketDiscountFeeList, String code, Double fee) {
        TicketDiscountFee ticketDiscountFee = filterTicketDiscountFee(ticketDiscountFeeList, code);
        fee = getDouble(ticketDiscountFee.getFee()) + fee;
        ticketDiscountFee.setFee(showMoneyDouble(fee));
    }

    /**
     * 给订单添加支付类型，操作是按位与
     *
     * @param payTypeBitInOrder
     * @param payType
     */
    public int addPayTypeBit(int payTypeBitInOrder, int payType) {
        int bitNumber = 1 << payType - 1;
        return payTypeBitInOrder | bitNumber;
    }

    /**
     * 计算支付订单的位运算
     *
     * @param orderList
     * @return
     */
    public int calPayTypeBit(List<Order> orderList) {
        int payTypeBit = 0;
        for (Order order : orderList) {
            payTypeBit = addPayTypeBit(payTypeBit, order.getPayType());
        }

        return payTypeBit;
    }

    /**
     * 处理订单里面的套餐
     *
     * @param order
     */
    public void upgradeSetMenuItemInOrder(Order order) {
        if (order == null) {
            return;
        }

        List<OrderItem> orderItemList = getList(order.getOrderItemDetailList());

        for (OrderItem orderItem : orderItemList) {
            if (!getBoolean(orderItem.getSetMenu())) {
                continue;
            }

            List<SetMenuOneItem> setMenuOneItemList = getList(orderItem.getSetMenuOneItemList());
            for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
                List<Item> itemList = getList(setMenuOneItem.getItemList());
                for (Item item : itemList) {
                    if (item.getCountInOrder() == null) {
                        item.setCountInOrder(1);
                    }
                }
            }
        }
    }

    /**
     * 套餐里面的菜的个数
     *
     * @param item
     * @return
     */
    public int getCountInOrder(Item item) {
        if (getInt(item.getCountInOrder()) <= 0) {
            return 1;
        }

        return item.getCountInOrder();
    }

    /**
     * 修改订单的支付类型
     *
     * @param order
     */
    public void modifyOrderPayType(Order order) throws Exception {
        Order orderInDb = findOrder(order.getShopId(), order.getId());
        VerifyUtil.verify(() -> orderInDb.getStatus() == ORDER_STATUS_END, ORDER_RETURN_CASH_CAN_NOT_MODIFY_PAY_TYPE);
        //不能是第3方付款
        VerifyUtil.verify(() -> !getBoolean(orderInDb.getPayedWith3rd()));
        VerifyUtil.verify(() -> isNotEmpty(order.getPayType()));
        //父订单一定是单独结账
        if (getBoolean(orderInDb.getParentOrder())) {
            VerifyUtil.verify(() -> getInt(orderInDb.getUserSelectPayType()) == USER_SELECT_PAY_TYPE_ONE_USER);
        }

        ThreadContext.put(THREAD_LOCAL_VARIABLE_MODIFY_ORDER_PAY_TYPE, "true");

        try {

            //修改支付方式的日志
            OrderOpLogService opLogService = OrderOpLogService.getInstance();
            OrderOpLog orderOpLog = opLogService.content(orderInDb, CHANGE_PAY_TYPE);
            opLogService.changePayTypeLog(order, orderOpLog);

            //处理子订单的方法
            if (getBoolean(orderInDb.getSubOrder())) {
                modifySubOrderPayType(orderInDb, order);
                Order parentOrder = findOrder(order.getShopId(), orderInDb.getParentOrderId());
                List<Order> payedOrderList = findPayOrderWithSubOrderId(orderInDb);
                //处理支付订单的方法
                for (Order payOrder : payedOrderList) {
                    modifyPayOrderPayType(payOrder, order);
                }
                modifyParentOrderPayType(parentOrder, order);
            } else if (getBoolean(orderInDb.getParentOrder())) {
                List<Order> payedOrderList = findPayedOrder(order.getShopId(), orderInDb.getId());
                //处理支付订单的方法
                for (Order payOrder : payedOrderList) {
                    modifyPayOrderPayType(payOrder, order);
                }
                modifyParentOrderPayType(orderInDb, order);
            }


        } finally {
            ThreadContext.remove(THREAD_LOCAL_VARIABLE_MODIFY_ORDER_PAY_TYPE);
        }


    }

    /**
     * 修改父订单
     *
     * @param parentOrder
     * @param payOrder
     * @throws Exception
     */
    private void modifyParentOrderPayType(Order parentOrder, Order payOrder) throws Exception {
        //计算父订单支付类型的二进制值
        parentOrder = payTypeBitToParentPayOrder(parentOrder);
        //根据二进制值，把支付方式的中英文设置到订单
        parentOrder = payTypeNameToParentOrder(parentOrder);
        //修改cashPay
        parentCashPayNameList(parentOrder, payOrder);
    }

    /**
     * 把支付方式的中英文设置到父订单
     *
     * @param parentOrder
     * @return
     * @throws Exception
     */
    private Order payTypeNameToParentOrder(Order parentOrder) throws Exception {
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(parentOrder);
        parentOrder.setPayTypeNameList(payTypeNameList);
        commonService.save(parentOrder);
        return parentOrder;

    }

    /**
     * 计算父订单支付类型的Bit值
     *
     * @param parentOrder
     * @return
     * @throws Exception
     */
    private Order payTypeBitToParentPayOrder(Order parentOrder) throws Exception {
        List<Order> payedOrderList = findPayedOrder(parentOrder.getShopId(), parentOrder.getId());
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(parentOrder);
        int payTypeBit = calPayTypeBit(payedOrderList);
        payTypeNameList = payTypeNameList.stream()
                .collect(Collectors.collectingAndThen(Collectors.toCollection(()
                        -> new TreeSet<>(Comparator.comparing(s -> s.getName_zh() + ";" + s.getName_en()))), ArrayList::new));
        parentOrder.setPayTypeNameList(payTypeNameList);
        parentOrder.setPayTypeBit(payTypeBit);
        commonService.save(parentOrder);
        return parentOrder;
    }

    /**
     * 修改父订单的cashPay
     *
     * @param parentOrder
     * @param payOrder
     * @return
     * @throws Exception
     */
    private Order parentCashPayNameList(Order parentOrder, Order payOrder) throws Exception {
        //找到对应的支付订单
        List<Order> payedOrderList = findPayedOrder(parentOrder.getShopId(), parentOrder.getId());
        Order orderInDb = findOrder(payOrder.getShopId(), payOrder.getId());
        //找到要修改的指定订单
        if (getBoolean(orderInDb.getSubOrder())) {
            payedOrderList = payedOrderList.stream().filter(s -> equals(s.getRelatedSubOrderId(), payOrder.getId())).collect(Collectors.toList());
        }

        //对应的一个支付成功的支付订单
        if (isEmpty(payedOrderList)) {
            logger.info("pay order is null");
            return parentOrder;
        }

        Order onePayOrder = payedOrderList.get(0);
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(onePayOrder);
        for (PayTypeName payTypeName : payTypeNameList) {
            //处理父订单cashPayList
            if (isNotEmpty(parentOrder)) {
                List<CashPay> parentCashPayList = parentOrder.getCashPayList();
                for (CashPay cashPay : parentOrder.getCashPayList()) {
                    if (equals(cashPay.getOrderId(), onePayOrder.getId())) {
                        cashPay.setPayType(payOrder.getPayType());
                        cashPay.setPayTypeName_zh(payTypeName.getName_zh());
                        cashPay.setPayTypeName_en(payTypeName.getName_en());
                    }

                }
                parentOrder.setCashPayList(parentCashPayList);
            }

        }

        commonService.save(parentOrder);

        return parentOrder;
    }

    /**
     * 修改支付订单
     *
     * @param payOrder
     * @param refOrder
     * @throws Exception
     */
    private void modifyPayOrderPayType(Order payOrder, Order refOrder) throws Exception {
        //计算支付类型的二进制值
        payOrder = payTypeBitToPayOrder(payOrder, refOrder);
        //根据二进制值，把支付方式的中英文设置到订单
        payOrder = payTypeNameToPayOrder(payOrder);
        //cashPay改变中英文
        payOrderCashPayName(payOrder, refOrder.getPayType());


    }

    /**
     * 修改支付订单的cashPay
     *
     * @param payOrder
     * @param payType
     * @return
     * @throws Exception
     */
    private Order payOrderCashPayName(Order payOrder, Integer payType) throws Exception {
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(payOrder);
        for (PayTypeName payTypeName : payTypeNameList) {
            List<CashPay> cashPayList = payOrder.getCashPayList();
            for (CashPay cashPay : cashPayList) {
                cashPay.setPayType(payType);
                cashPay.setPayTypeName_zh(payTypeName.getName_zh());
                cashPay.setPayTypeName_en(payTypeName.getName_en());
            }
            payOrder.setCashPayList(cashPayList);
        }
        commonService.save(payOrder);
        return payOrder;
    }

    /**
     * 设置支付类型的名称中英文到订单
     *
     * @param payOrder
     * @return
     * @throws Exception
     */
    private Order payTypeNameToPayOrder(Order payOrder) throws Exception {
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(payOrder);
        for (PayTypeName payTypeName : payTypeNameList) {
            payOrder.setPayTypeName_zh(payTypeName.getName_zh());
            payOrder.setPayTypeName_en(payTypeName.getName_en());
        }
        payOrder.setPayTypeNameList(payTypeNameList);
        commonService.save(payOrder);
        return payOrder;
    }


    /**
     * 设置支付方式二进制值
     *
     * @param payOrder
     * @param refOrder
     * @return
     * @throws Exception
     */
    private Order payTypeBitToPayOrder(Order payOrder, Order refOrder) throws Exception {
        List<Integer> arrayList = new ArrayList<>();
        arrayList.add(refOrder.getPayType());
        long payTypeBitInt = intListToBitNumber(arrayList);
        payOrder.setPayType(refOrder.getPayType());
        payOrder.setPayTypeBit((int) payTypeBitInt);
        commonService.save(payOrder);
        return payOrder;
    }

    /**
     * 修改子订单的支付类型
     *
     * @param subOrder
     * @param refOrder
     * @throws Exception
     */
    private void modifySubOrderPayType(Order subOrder, Order refOrder) throws Exception {
        //计算支付类型的二进制值
        subOrder = payTypeBitToSubOrder(subOrder, refOrder);
        //根据二进制值，把支付方式的中英文设置到订单
        subOrder = payTypeNameToSubOrder(subOrder);

        commonService.save(subOrder);

    }

    /**
     * 支付方式的中英文设置到子订单
     *
     * @param subOrder
     * @return
     * @throws Exception
     */
    private Order payTypeNameToSubOrder(Order subOrder) throws Exception {
        List<PayTypeName> payTypeNameList = PayTypeService.getInstance().filterOrderPayTypeNameList(subOrder);
        for (PayTypeName payTypeName : payTypeNameList) {
            subOrder.setPayTypeName_zh(payTypeName.getName_zh());
            subOrder.setPayTypeName_en(payTypeName.getName_en());
        }
        subOrder.setPayTypeNameList(payTypeNameList);
        commonService.save(subOrder);
        return subOrder;
    }

    /**
     * 计算子订单的payTypeBit值
     *
     * @param subOrder
     * @param refOrder
     * @return
     */
    private Order payTypeBitToSubOrder(Order subOrder, Order refOrder) throws Exception {
        List<Integer> arrayList = new ArrayList<>();
        arrayList.add(refOrder.getPayType());
        long payTypeBitInt = intListToBitNumber(arrayList);
        subOrder.setPayType(refOrder.getPayType());
        subOrder.setPayTypeBit((int) payTypeBitInt);
        commonService.save(subOrder);
        return subOrder;
    }

    /**
     * 已支付的订单转化成支付订单的请求参数
     *
     * @param order
     * @return
     */
    public PayOrder createPayOrderWithExistOrder(Order order) {
        PayOrder payOrder = new PayOrder();
        payOrder.setShopId(order.getShopId());
        payOrder.setOrderId(order.getId());

        payOrder.setCustomerId(order.getCustomerId());
        payOrder.setTicketCodeList(order.getTicketCodeList());

        return payOrder;
    }

    /**
     * 是否是自定义的外卖订单
     *
     * @param order
     * @return
     */
    public boolean isCustomizedTakeoutOrder(Order order) {
        return order.getTakeoutSettingId() != null;
    }

    /**
     * 删除订单
     *
     * @param order
     */
    public void realDeleteOrder(Order order) throws Exception {
        Long orderId = order.getId();
        Long shopId = order.getShopId();
        VerifyUtil.verify(() -> orderId != null);
        VerifyUtil.verify(() -> shopId != null);

        commonService.delete(order);
    }

    /**
     * 查询刷卡机支付的订单
     *
     * @param shopId
     */
    public List<Order> findStripeTerminalPayedOrder(Long shopId) throws Exception {
        Shop shop = ShopService.getInstance().findShopById(shopId);
        Long openTime = shop.getOpenTime();
        Order order = new Order();
        order.setShopId(shopId);
        order.setStartCreateTime(openTime);
        order.setStripeTerminal(true);

        List<Order> orderList = commonService.searchAll(order);
        //过滤已支付的订单，过滤未退款的订单
        //只能是父订单或者是子订单
        orderList = orderList.stream().filter(p -> getBoolean(p.getPayed()) && !getBoolean(p.getReturnCash())).filter(p -> getBoolean(p.getParentOrder()) || getBoolean(p.getSubOrder())).collect(Collectors.toList());

        return orderList;
    }

    /**
     * C端用户，一个人付款，并且选择了现金支付
     *
     * @param orderInDB
     * @return
     */
    public boolean oneUserPayAndSelectCash(Order orderInDB) {
        if (orderInDB == null) {
            logger.info("order is empty");
            return false;
        }

        int userSelectPayType = getInt(orderInDB.getUserSelectPayType());
        if (userSelectPayType != USER_SELECT_PAY_TYPE_ONE_USER) {
            logger.info("not the one user pay type");
            return false;
        }

        List<LockOrderCashOrOrderItem> lockOrderCashOrOrderItems = getList(orderInDB.getLockOrderCashOrOrderItemList());
        if (isEmpty(lockOrderCashOrOrderItems)) {
            logger.info("lock cash item list is empty");
            return false;
        }

        Optional<LockOrderCashOrOrderItem> lockOrderCashOrOrderItemOptional = lockOrderCashOrOrderItems.stream().filter(lockOrderCashOrOrderItem -> getInt(lockOrderCashOrOrderItem.getPayType()) == ORDER_PAY_TYPE_CASH).findAny();
        return lockOrderCashOrOrderItemOptional.isPresent();
    }

    /**
     * 将orderItem转化成itemNumber
     *
     * @param orderItem
     * @return
     */
    public List<ItemNumber> orderItemToItemNumber(OrderItem orderItem) throws Exception {
        OrderService orderService = OrderService.getInstance();

        Long itemId = orderItem.getItemId();
        Item itemInDb = ItemService.getInstance().findItem(itemId);
        Integer orderItemCount = orderItem.getCount();

        if (orderItemCount == null) {
            orderItemCount = 1;
        }

        Set<ItemNumber> itemNumberSet = new HashSet<>();

        {
            //添加本身自己的锁定量
            ItemNumber itemNumber = new ItemNumber(orderItem.getItemId(), orderItemCount);
            itemNumberSet.add(itemNumber);
        }

        if (getBoolean(itemInDb.getSetMenu())) {
            List<SetMenuOneItem> setMenuOneItemList = getList(orderItem.getSetMenuOneItemList());
            List<Item> itemList = setMenuOneItemList.stream().flatMap(p -> getList(p.getItemList()).stream()).collect(Collectors.toList());

            for (Item item : itemList) {
                Optional<ItemNumber> itemLockNumberOptional = itemNumberSet.stream().filter(p -> equals(p.getItemId(), item.getId())).findAny();
                if (itemLockNumberOptional.isPresent()) {
                    ItemNumber itemLockNumber = itemLockNumberOptional.get();
                    itemLockNumber.setNumber(itemLockNumber.getNumber() + orderItemCount * orderService.getCountInOrder(item));
                } else {
                    ItemNumber itemLockNumber = new ItemNumber(item.getId(), orderItemCount * orderService.getCountInOrder(item));
                    itemNumberSet.add(itemLockNumber);
                }
            }
        }

        return new ArrayList<>(itemNumberSet.stream().filter(p -> getLong(p.getItemId()) != 0).collect(Collectors.toList()));
    }

    /**
     * orderItem里面的第一个菜
     *
     * @param orderItem
     */
    public List<Item> orderItemToItemList(OrderItem orderItem) throws Exception {
        List<ItemNumber> itemNumbers = orderItemToItemNumber(orderItem);
        return itemNumbers.stream().map(itemNumber -> {
            try {
                return ItemService.getInstance().findItem(itemNumber.getItemId());
            } catch (Exception e) {
                logger.error("e", e);
                return null;
            }
        }).filter(item -> item != null).collect(Collectors.toList());
    }

    /**
     * 是否是更新或者删除订单的操作
     *
     * @param reqOrder
     * @return
     */
    public boolean isUpdateOrDeleteAction(Order reqOrder) {
        OrderItem reqOrderItem = getList(reqOrder.getOrderItemDetailList()).get(0);

        boolean b = reqOrderItem.getId() != null;
        logger.info("update delete action {}", b);
        return b;
    }

    public boolean isCustomerRequest(Order reqOrder) {
        boolean customerRequest = false;
        if (getBoolean(reqOrder.getCustomerRequest())) {
            customerRequest = true;
        } else {
            customerRequest = ServletUtil.getUserId() == null;
        }
        return customerRequest;
    }

    /**
     * 营业流水表头总计
     *
     * @param order
     * @return
     * @throws ResponseStatusException
     */
    public List<Order> findOrderTotal(Order order) throws ResponseStatusException {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        //得到实际支付总金额，只有一个对象
        List<CashPay> CashPayList = getCashPayList(order);
        List<Tuple> tuples = null;
        long payTypeBitNumber = intListToBitNumber(order.getPayTypeList());
        //带支付方式统计
        if (isNotEmpty(order.getPayTypeList())) {
            //带支付方式计算
            tuples = orderDao.orderHeaderTotalPayType(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId(), payTypeBitNumber);
        } else {
            //不带支付方式计算
            tuples = orderDao.orderHeaderTotal(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId());
        }
        List<Order> orderList = tuples.stream().map(p -> {
            Order orderTuple = new Order();
            NativeResultProcessUtils.convertTupleToBean(p, orderTuple);
            //补偿方案。不知道为什么。int 到Tuple里面变成BigDecimal类型
            BigDecimal personsBigDecimal = (BigDecimal) p.get(2);
            int intPersons = personsBigDecimal.intValue();
            orderTuple.setPersons(intPersons);
            //总实际支付的钱
            orderTuple.setCashPayList(CashPayList);
            return orderTuple;
        }).collect(Collectors.toList());
        return orderList;
    }

    //得到实际支付总金额
    public List<CashPay> getCashPayList(Order order) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(8);
        statusList.add(9);
        statusList.add(10);
        CashPay cashPay = new CashPay();
        List<CashPay> CashPayList = new ArrayList<>();
        if (isNotEmpty(order.getPayTypeList())) {
            long payTypeBitNumber = intListToBitNumber(order.getPayTypeList());
            //获取到非100的实际支付金额
            List<Order> orderList = orderDao.idOrderHeaderTotalNon100(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId(), payTypeBitNumber, statusList);
            //获取到失效订单
            List<Order> expiredOrderList = orderDao.idExpiredOrderList(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId(), payTypeBitNumber);
            orderList.addAll(expiredOrderList);
            Double cashPayNon100 = sumCashPay(orderList);
            //获取到100的实际支付金额
            Double total100 = orderDao.idOrderHeaderTotal100(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId(), payTypeBitNumber);
            //总共的实际支付金额
            cashPay.setPayCash(cashPayNon100 + total100);
            CashPayList.add(cashPay);
            return CashPayList;
        }
        //获取到非100的实际支付金额
        List<Order> orderListNon100 = orderDao.orderHeaderTotalNon100(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId(), statusList);

        //获取到失效订单
        List<Order> expiredOrderList = orderDao.expiredOrderList(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId());
        orderListNon100.addAll(expiredOrderList);
        Double cashPayNon100 = sumCashPay(orderListNon100);
        //获取到100的实际支付金额
        Double total100 = orderDao.orderHeaderTotal100(order.getStartCreateTime(), order.getEndCreateTime(), order.getShopId());
        //总共的实际支付金额
        cashPay.setPayCash(cashPayNon100 + total100);
        CashPayList.add(cashPay);
        return CashPayList;
    }

    private Double sumCashPay(List<Order> orderList) {
        Double cashPayTotal = 0.0;
        List<String> collect = orderList.stream().map(s -> s.getCashPayJson()).collect(Collectors.toList());
        for (String cashPay : collect) {
            //补偿，查询出来没有自己转为List，手动转换
            List<CashPay> list = JSON.parseArray(cashPay, CashPay.class);
            if (isNotEmpty(list)) {
                for (CashPay pay : list) {
                    Double payCash = null;
                    if (isNotEmpty(pay.getReturnCash())) {
                        payCash = pay.getPayCash() - pay.getReturnCash();
                    } else {
                        payCash = pay.getPayCash();
                    }
                    cashPayTotal = cashPayTotal + payCash;
                }
            }

        }

        return cashPayTotal;
    }

    public Order createRechargePayOrder(Order order) throws Exception {
        Integer orderNo = createOrderNo(order.getShopId());
        order.setOrderNo(orderNo);
        order.setSubOrderId(null);
        String sessionId = ServletUtil.getSessionId();
        order.setLastOperateSession(sessionId);
        order.setStatus(ORDER_STATUS_PENDING_PAY);
        order.setCreateTime(System.currentTimeMillis());
        order.setRequestId(null);
        order.setOnlinePay(true);
        order.setBusinessEndShow(false);
        order.setReturnCash(false);
        order.setPayed(false);
        order.setDiscountFee(null);
        order.setCustomerPayOrder(true);
        order.setSessionId(sessionId);
        order.setSubOrder(false);
        order.setCashPayList(null);
        order.setCashPayJson(null);
        order.setRechargeOrder(true);
        return order;
    }

    /**
     * 打包费，小计百分比计算
     *
     * @param order
     */
    public void packageFeeCompute(Order order) throws Exception {
        Shop shop = ShopService.getInstance().findShopById(order.getShopId());
        ShopConfig shopConfig = shop.getShopConfig();
        if (equals(order.getOrderType(), ORDER_TYPE_TAKE_OUT) && equals(getInt(shopConfig.getPackageFeeSelect()), PACKAGE_FEE_PERCENT)) {
            order.setPackageFee(showMoneyDouble(order.getCostOrigin() * getDouble(shopConfig.getPackageFeePercent()) / 100));
        }

    }

}
